Skip to content

Commit

Permalink
Display group plan info in admin panel
Browse files Browse the repository at this point in the history
  • Loading branch information
phillipthelen committed Dec 3, 2024
1 parent 45c70db commit b7df7d6
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 9 deletions.
2 changes: 1 addition & 1 deletion website/client/src/components/admin-panel/search.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<loading-spinner
v-if="isSearching"
class="mx-auto mb-2"
dark-color="true"
dark-color=true

Check warning on line 13 in website/client/src/components/admin-panel/search.vue

View workflow job for this annotation

GitHub Actions / production-build (21.x)

Expected to be enclosed by double quotes

Check warning on line 13 in website/client/src/components/admin-panel/search.vue

View workflow job for this annotation

GitHub Actions / production-build (21.x)

Expected to be enclosed by double quotes
/>
<div
v-if="users.length > 0"
Expand Down
10 changes: 10 additions & 0 deletions website/client/src/components/admin-panel/user-support/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

<subscription-and-perks
:hero="hero"
:group-plans="groupPlans"
:has-unsaved-changes="hasUnsavedChanges([hero.purchased.plan,
unModifiedHero.purchased.plan])"
/>
Expand Down Expand Up @@ -179,6 +180,7 @@ export default {
unModifiedHero: {},
hero: {},
party: {},
groupPlans: [],
hasParty: false,
partyNotExistError: false,
adminHasPrivForParty: true,
Expand Down Expand Up @@ -237,6 +239,14 @@ export default {
}
}
if (this.hero.purchased.plan.planId === 'group_plan_auto') {
try {
this.groupPlans = await this.$store.dispatch('hall:getHeroGroupPlans', { heroId: this.hero._id });
} catch (e) {
this.groupPlans = [];
}
}
this.resetCounter += 1; // tell child components to reinstantiate from scratch
},
hasUnsavedChanges (...comparisons) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
class="form-control"
type="text"
>
<option value="Group Plan">Group Plan</option>
<option value="groupPlan">Group Plan</option>
<option value="Stripe">Stripe</option>
<option value="Apple">Apple</option>
<option value="Google">Google</option>
Expand Down Expand Up @@ -96,14 +96,39 @@
<div class="form-group row"
v-if="hero.purchased.plan.planId === 'group_plan_auto'">
<label class="col-sm-3 col-form-label">
Group Plan group ID:
Group Plan Memberships:
</label>
<div class="col-sm-9">
<input
v-model="hero.purchased.plan.owner"
class="form-control"
type="text"
>
<div class="col-sm-9 col-form-label">
<loading-spinner
v-if="!groupPlans"
dark-color=true
/>
<b
v-else-if="groupPlans.length === 0"
class="text-danger col-form-label"
>User is not part of an active group plan!</b>
<div
v-else
v-for="group in groupPlans"
:key="group._id"
class="card mb-2">
<div class="card-body">
<h6 class="card-title">{{ group.name }}
<small class="float-right">{{ group._id }}</small>
</h6>
<p class="card-text">
<strong>Leader: </strong>
<a
v-if="group.leader !== hero._id"
@click="switchUser(group.leader)"
>{{ group.leader }}</a>
<strong v-else class="text-success">This user</strong>
</p>
<p class="card-text">
<strong>Members: </strong> {{ group.memberCount }}
</p>
</div>
</div>
</div>
</div>
<div
Expand Down Expand Up @@ -378,9 +403,13 @@ import moment from 'moment';
import { getPlanContext } from '@/../../common/script/cron';
import saveHero from '../mixins/saveHero';
import subscriptionBlocks from '../../../../../common/script/content/subscriptionBlocks';
import LoadingSpinner from '@/components/ui/loadingSpinner';
export default {
mixins: [saveHero],
components: {
LoadingSpinner,
},
props: {
hero: {
type: Object,
Expand All @@ -390,6 +419,10 @@ export default {
type: Boolean,
required: true,
},
groupPlans: {
type: Array,
default: null,
},
},
data () {
return {
Expand All @@ -411,6 +444,7 @@ export default {
},
isRegularPaymentMethod () {
return [
'groupPlan',
'Group Plan',
'Stripe',
'Apple',
Expand Down Expand Up @@ -460,6 +494,11 @@ export default {
this.saveHero({ hero: this.hero, msg: 'Subscription Perks' });
}
},
switchUser (id) {
if (window.confirm('Switch to this user?')) {
this.$emit('changeUserIdentifier', id);
}
},
},
};
</script>
6 changes: 6 additions & 0 deletions website/client/src/store/actions/hall.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,9 @@ export async function getHeroParty (store, payload) {
const response = await axios.get(url);
return response.data.data;
}

export async function getHeroGroupPlans (store, payload) {
const url = `/api/v4/hall/heroes/${payload.heroId}/group-plans`;
const response = await axios.get(url);
return response.data.data;
}
62 changes: 62 additions & 0 deletions website/server/controllers/api-v3/hall.js
Original file line number Diff line number Diff line change
Expand Up @@ -551,4 +551,66 @@ api.getHeroParty = { // @TODO XXX add tests
},
};

/**
* @api {get} /api/v3/hall/heroes/:heroId Get Group Plans for a user
* @apiParam (Path) {UUID} groupId party's group ID
* @apiName GetHeroGroupPlans
* @apiGroup Hall
* @apiPermission userSupport
*
* @apiDescription Returns some basic information about group plans,
* to assist admins with user support.
*
* @apiSuccess {Object} data The active group plans
*
* @apiUse NoAuthHeaders
* @apiUse NoAccount
* @apiUse NoUser
* @apiUse NoPrivs
*/
api.getHeroGroupPlans = {
method: 'GET',
url: '/hall/heroes/:heroId/group-plans',
middlewares: [authWithHeaders(), ensurePermission('userSupport')],
async handler (req, res) {
req.checkParams('heroId', res.t('heroIdRequired')).notEmpty();

const validationErrors = req.validationErrors();
if (validationErrors) throw validationErrors;

const { heroId } = req.params;

let query;
if (validator.isUUID(heroId)) {
query = { _id: heroId };
} else {
query = { 'auth.local.lowerCaseUsername': heroId.toLowerCase() };
}

const hero = await User
.findOne(query)
.select('guilds party')
.exec();

if (!hero) throw new NotFound(res.t('userWithIDNotFound', { userId: heroId }));
const heroGroups = hero.getGroups();

if (heroGroups.length === 0) {
res.respond(200, []);
return;
}

const groups = await Group
.find({
_id: { $in: heroGroups },
})
.select('leaderOnly leader purchased name managers memberCount')
.exec();

const groupPlans = groups.filter(group => group.hasActiveGroupPlan());

res.respond(200, groupPlans);
},
};

export default api;

0 comments on commit b7df7d6

Please sign in to comment.