diff --git a/ghost/admin/app/components/gh-member-avatar.js b/ghost/admin/app/components/gh-member-avatar.js
index abffe1d1b4..4f1ec98979 100644
--- a/ghost/admin/app/components/gh-member-avatar.js
+++ b/ghost/admin/app/components/gh-member-avatar.js
@@ -1,5 +1,4 @@
import Component from '@glimmer/component';
-import {get} from '@ember/object';
import {htmlSafe} from '@ember/template';
const stringToHslColor = function (str, saturation, lightness) {
@@ -16,15 +15,14 @@ export default class GhMemberAvatarComponent extends Component {
get memberName() {
let {member} = this.args;
- // can be given a proxy object from a sparse array so get is required
- return get(member, 'name') || get(member, 'email') || 'NM';
+ return member?.name || member?.email || 'NM';
}
get avatarImage() {
let {member} = this.args;
// to cover both ways avatar image is returned depending on where member data comes from
- return get(member, 'avatar_image') || get(member, 'avatarImage') || null;
+ return member?.avatar_image || member?.avatarImage || null;
}
get backgroundStyle() {
diff --git a/ghost/admin/app/components/gh-members-list-item-loading.hbs b/ghost/admin/app/components/gh-members-list-item-loading.hbs
new file mode 100644
index 0000000000..6442223d5a
--- /dev/null
+++ b/ghost/admin/app/components/gh-members-list-item-loading.hbs
@@ -0,0 +1,12 @@
+
+
+
+
+
+ {{#each @filterColumns}}
+
+ {{/each}}
+
\ No newline at end of file
diff --git a/ghost/admin/app/components/gh-members-list-item.hbs b/ghost/admin/app/components/gh-members-list-item.hbs
index 42cf9af6a2..08e98c0990 100644
--- a/ghost/admin/app/components/gh-members-list-item.hbs
+++ b/ghost/admin/app/components/gh-members-list-item.hbs
@@ -1,82 +1,69 @@
- {{#if @member.is_loading}}
-
-
-
-
- {{#each @filterColumns}}
-
- {{/each}}
- {{else}}
-
-
-
-
-
{{or @member.name @member.email}}
- {{#if @member.name}}
-
{{@member.email}}
- {{/if}}
-
+
+
+
+
+
{{or @member.name @member.email}}
+ {{#if @member.name}}
+
{{@member.email}}
+ {{/if}}
-
- {{#if this.hasMultipleTiers}}
-
- {{#if (not (is-empty @member.status))}}
- {{capitalize @member.status}}
- {{else}}
- -
- {{/if}}
- {{this.tiers}}
-
- {{else}}
-
- {{#if (not (is-empty @member.status))}}
- {{capitalize @member.status}}
- {{else}}
- -
- {{/if}}
-
- {{/if}}
- {{#if @newsletterEnabled}}
- {{#if (feature "emailAnalytics")}}
-
- {{#if (not (is-empty @member.emailOpenRate))}}
- {{@member.emailOpenRate}}%
- {{else}}
- N/A
- {{/if}}
-
- {{/if}}
- {{/if}}
-
-
- {{#if (and @member.geolocation @member.geolocation.country)}}
- {{#if (and (eq @member.geolocation.country_code "US") @member.geolocation.region)}}
- {{@member.geolocation.region}}, US
- {{else}}
- {{#if @member.geolocation.country}}
- {{@member.geolocation.country}}
- {{else}}
- Unknown
- {{/if}}
- {{/if}}
+
+
+ {{#if this.hasMultipleTiers}}
+
+ {{#if (not (is-empty @member.status))}}
+ {{capitalize @member.status}}
{{else}}
- Unknown
+ -
+ {{/if}}
+ {{this.tiers}}
+
+ {{else}}
+
+ {{#if (not (is-empty @member.status))}}
+ {{capitalize @member.status}}
+ {{else}}
+ -
{{/if}}
-
-
- {{#if @member.createdAtUTC}}
- {{moment-format (moment-site-tz @member.createdAtUTC) "DD MMM YYYY"}}
- {{moment-from-now @member.createdAtUTC}}
- {{/if}}
-
-
- {{#each @filterColumns as |filterColumn|}}
-
- {{/each}}
{{/if}}
+ {{#if @newsletterEnabled}}
+ {{#if (feature "emailAnalytics")}}
+
+ {{#if (not (is-empty @member.emailOpenRate))}}
+ {{@member.emailOpenRate}}%
+ {{else}}
+ N/A
+ {{/if}}
+
+ {{/if}}
+ {{/if}}
+
+
+ {{#if (and @member.geolocation @member.geolocation.country)}}
+ {{#if (and (eq @member.geolocation.country_code "US") @member.geolocation.region)}}
+ {{@member.geolocation.region}}, US
+ {{else}}
+ {{#if @member.geolocation.country}}
+ {{@member.geolocation.country}}
+ {{else}}
+ Unknown
+ {{/if}}
+ {{/if}}
+ {{else}}
+ Unknown
+ {{/if}}
+
+
+
+ {{#if @member.createdAtUTC}}
+ {{moment-format (moment-site-tz @member.createdAtUTC) "DD MMM YYYY"}}
+ {{moment-from-now @member.createdAtUTC}}
+ {{/if}}
+
+
+ {{#each @filterColumns as |filterColumn|}}
+
+ {{/each}}
diff --git a/ghost/admin/app/components/gh-members-list-item.js b/ghost/admin/app/components/gh-members-list-item.js
index 9330a59c51..4b3d22db8b 100644
--- a/ghost/admin/app/components/gh-members-list-item.js
+++ b/ghost/admin/app/components/gh-members-list-item.js
@@ -1,5 +1,4 @@
import Component from '@glimmer/component';
-import {get} from '@ember/object';
import {inject as service} from '@ember/service';
export default class GhMembersListItem extends Component {
@@ -14,7 +13,7 @@ export default class GhMembersListItem extends Component {
}
get tiers() {
- const tierData = get(this.args.member, 'tiers') || [];
+ const tierData = this.args.member?.tiers || [];
return tierData.map(tier => tier.name).join(', ');
}
}
diff --git a/ghost/admin/app/components/member/newsletter-preference.js b/ghost/admin/app/components/member/newsletter-preference.js
index d31ad6a397..9f957b8d05 100644
--- a/ghost/admin/app/components/member/newsletter-preference.js
+++ b/ghost/admin/app/components/member/newsletter-preference.js
@@ -1,5 +1,5 @@
import Component from '@glimmer/component';
-import {action, get} from '@ember/object';
+import {action} from '@ember/object';
import {tracked} from '@glimmer/tracking';
export default class MembersNewsletterPreference extends Component {
@@ -15,7 +15,7 @@ export default class MembersNewsletterPreference extends Component {
return {
name: d.name,
description: d.description,
- subscribed: !!this.args.member?.get('newsletters')?.find((n) => {
+ subscribed: !!this.args.member?.newsletters?.find((n) => {
return n.id === d.id;
}),
id: d.id,
@@ -34,14 +34,12 @@ export default class MembersNewsletterPreference extends Component {
return d.id === newsletter.id;
});
- // get() is required because member can be a proxy object when loaded
- // directly from the members list
if (!event.target.checked) {
- updatedNewsletters = get(this.args.member, 'newsletters').filter((d) => {
+ updatedNewsletters = this.args.member.newsletters.filter((d) => {
return d.id !== newsletter.id;
});
} else {
- updatedNewsletters = get(this.args.member, 'newsletters').filter((d) => {
+ updatedNewsletters = this.args.member.newsletters.filter((d) => {
return d.id !== newsletter.id;
}).concat(selectedNewsletter);
}
diff --git a/ghost/admin/app/controllers/member.js b/ghost/admin/app/controllers/member.js
index 96857501b2..563b9f11be 100644
--- a/ghost/admin/app/controllers/member.js
+++ b/ghost/admin/app/controllers/member.js
@@ -68,9 +68,8 @@ export default class MemberController extends Controller {
}
get subscribedAt() {
- // member can be a proxy object in a sparse array so .get is required
- let memberSince = moment(this.member.get('createdAtUTC')).from(moment());
- let createdDate = moment(this.member.get('createdAtUTC')).format('D MMM YYYY');
+ let memberSince = moment(this.member.createdAtUTC).from(moment());
+ let createdDate = moment(this.member.createdAtUTC).format('D MMM YYYY');
return `${createdDate} (${memberSince})`;
}
@@ -133,7 +132,7 @@ export default class MemberController extends Controller {
// if Cmd+S is pressed before the field loses focus make sure we're
// saving the intended property values
let scratchProps = scratchMember.getProperties(SCRATCH_PROPS);
- member.setProperties(scratchProps);
+ Object.assign(member, scratchProps);
try {
yield member.save();
@@ -178,7 +177,7 @@ export default class MemberController extends Controller {
// Private -----------------------------------------------------------------
_saveMemberProperty(propKey, newValue) {
- let currentValue = this.member.get(propKey);
+ let currentValue = this.member[propKey];
if (newValue && typeof newValue === 'string') {
newValue = newValue.trim();
@@ -189,6 +188,6 @@ export default class MemberController extends Controller {
return;
}
- this.member.set(propKey, newValue);
+ this.member[propKey] = newValue;
}
}
diff --git a/ghost/admin/app/routes/member.js b/ghost/admin/app/routes/member.js
index 905b70be4e..b1795592a2 100644
--- a/ghost/admin/app/routes/member.js
+++ b/ghost/admin/app/routes/member.js
@@ -30,9 +30,7 @@ export default class MembersRoute extends AdminRoute {
setupController(controller, member) {
super.setupController(...arguments);
if (this._requiresBackgroundRefresh) {
- // `member` is passed directly in `` so it can be a proxy
- // object used by the sparse list requiring the use of .get()
- controller.fetchMemberTask.perform(member.get('id'));
+ controller.fetchMemberTask.perform(member.id);
}
}
diff --git a/ghost/admin/app/routes/offer.js b/ghost/admin/app/routes/offer.js
index 1f2bf1643c..d90111cffa 100644
--- a/ghost/admin/app/routes/offer.js
+++ b/ghost/admin/app/routes/offer.js
@@ -23,9 +23,7 @@ export default class OffersRoute extends AdminRoute {
super.setupController(...arguments);
if (this._requiresBackgroundRefresh) {
- // `offer` is passed directly in `` so it can be a proxy
- // object used by the sparse list requiring the use of .get()
- controller.fetchOfferTask.perform(offer.get('id'));
+ controller.fetchOfferTask.perform(offer.id);
}
}
diff --git a/ghost/admin/app/templates/members.hbs b/ghost/admin/app/templates/members.hbs
index 7d821b1165..903c9a944b 100644
--- a/ghost/admin/app/templates/members.hbs
+++ b/ghost/admin/app/templates/members.hbs
@@ -126,12 +126,19 @@
-
+ {{#if member.is_loading}}
+
+ {{else}}
+
+ {{/if}}