Achievement list renovation & Achievements API (#7904)

* pull apart achievements into different subcategories

* achievs previously hidden to others if unachieved are now always shown

* achievs previously always hidden if unachieved are now always shown

* pull apart ultimate gear achievs

* add achiev wrapper mixin

* add achiev mixin for simple counts

* add achiev mixin for singular/plural achievs

* add simpleAchiev mixin and support attributes

* always hide potentially unearnable achievs if unearned

* contributor achiev now uses string interpolation for readMore link

* transition to basic achiev grid layout

* fix npc achievement img bug introduced in c90f7e2

* move surveys and contributor achievs into special section so it is never empty

* double size of achievs in achievs grid

* achievs in grid are muted if unachieved (includes recompiled sprites)

* fix streak notification strings

* add counts to achievement badges for applicable achieved achievs

* list achievements by api

* fix achievement strings in new api

* unearned achievs now use dedicated (WIP) 'unearned' badge instead of muted versions of the normal badges

* fix & cleanup achievements api

* extract generation of the achievements result to a class

* clean up achievement counter css using existing classes

* simplify exports of new achievementBuilder lib

* remove class logic from achievementBuilder lib

* move achievs to common, add rebirth achiev logic, misc fixes

* replace achievs jade logic with results of api call

* fix linting errors

* achievs lib now returns achievs object subdivided by type (basic/seasonal/special

* add tests for new achievs lib

* fix linting errors

* update controllers and views for updated achievs lib

* add indices to achievements to preserve intended order

* move achiev popovers to left

* rename achievs lib to achievements

* adjust positioning of achieve popovers now that stats and achievs pages
are separate

* fix: achievements api correctly decides whether to append extra string for master and triadBingo achievs

* revert compiled sprites so they don't bog down the PR

* pull out achievs api integration tests

* parameterize ultimate gear achievements' text string

* break out static achievement data from user-specific data

* reorg content.achievements to add achiev data in related chunks

* cleanup, respond to feedback

* improve api documentation

* fix merge issues

* Helped Habit Grow --> Helped Habitica Grow

* achievement popovers are muted if the achiev is unearned

* fix singular achievement labels / achievement popover on click

* update apidoc for achievements (description, param-type, successExample, error-types)

* fix whitespace issues in members.js

* move html to a variable

* updated json example

* fix syntax after merge
This commit is contained in:
Kaitlin Hipkin
2016-12-13 13:48:18 -05:00
committed by Keith Holliday
parent 97e1d75dce
commit 0817cf96e1
27 changed files with 1091 additions and 290 deletions

View File

@@ -17,6 +17,7 @@ import {
} from '../../libs/email';
import Bluebird from 'bluebird';
import { sendNotification as sendPushNotification } from '../../libs/pushNotifications';
import { achievements } from '../../../../website/common/';
let api = {};
@@ -58,6 +59,113 @@ api.getMember = {
},
};
/**
* @api {get} /api/v3/members/:memberId/achievements Get member achievements object
* @apiName GetMemberAchievements
* @apiGroup Member
* @apiDescription Get a list of achievements of the requested member, grouped by basic / seasonal / special.
*
* @apiParam (Path) {UUID} memberId The member's id
*
* @apiSuccess {Object} data The achievements object
*
* @apiSuccess {Object} data.basic The basic achievements object
* @apiSuccess {Object} data.seasonal The seasonal achievements object
* @apiSuccess {Object} data.special The special achievements object
*
* @apiSuccess {String} data.*.label The label for that category
* @apiSuccess {Object} data.*.achievements The achievements in that category
*
* @apiSuccess {String} data.*.achievements.title The localized title string
* @apiSuccess {String} data.*.achievements.text The localized description string
* @apiSuccess {Boolean} data.*.achievements.earned Whether the user has earned the achievement
* @apiSuccess {Number} data.*.achievements.index The unique index assigned to the achievement (only for sorting purposes)
* @apiSuccess {Anything} data.*.achievements.value The value related to the achievement (if applicable)
* @apiSuccess {Number} data.*.achievements.optionalCount The count related to the achievement (if applicable)
*
* @apiSuccessExample {json} Successful Response
* {
* basic: {
* label: "Basic",
* achievements: {
* streak: {
* title: "0 Streak Achievements",
* text: "Has performed 0 21-day streaks on Dailies",
* icon: "achievement-thermometer",
* earned: false,
* value: 0,
* index: 60,
* optionalCount: 0
* },
* perfect: {
* title: "5 Perfect Days",
* text: "Completed all active Dailies on 5 days. With this achievement you get a +level/2 buff to all attributes for the next day. Levels greater than 100 don't have any additional effects on buffs.",
* icon: "achievement-perfect",
* earned: true,
* value: 5,
* index: 61,
* optionalCount: 5
* }
* }
* },
* seasonal: {
* label: "Seasonal",
* achievements: {
* habiticaDays: {
* title: "Habitica Naming Day",
* text: "Celebrated 0 Naming Days! Thanks for being a fantastic user.",
* icon: "achievement-habiticaDay",
* earned: false,
* value: 0,
* index: 72,
* optionalCount: 0
* }
* }
* },
* special: {
* label: "Special",
* achievements: {
* habitSurveys: {
* title: "Helped Habitica Grow",
* text: "Helped Habitica grow on 0 occasions, either by filling out a survey or helping with a major testing effort. Thank you!",
* icon: "achievement-tree",
* earned: false,
* value: 0,
* index: 88,
* optionalCount: 0
* }
* }
* }
* }
*
* @apiError (400) {BadRequest} MemberIdRequired The `id` param is required and must be a valid `UUID`
* @apiError (404) {NotFound} UserWithIdNotFound The `id` param did not belong to an existing member
*/
api.getMemberAchievements = {
method: 'GET',
url: '/members/:memberId/achievements',
middlewares: [],
async handler (req, res) {
req.checkParams('memberId', res.t('memberIdRequired')).notEmpty().isUUID();
let validationErrors = req.validationErrors();
if (validationErrors) throw validationErrors;
let memberId = req.params.memberId;
let member = await User
.findById(memberId)
.select(memberFields)
.exec();
if (!member) throw new NotFound(res.t('userWithIDNotFound', {userId: memberId}));
let achievsObject = achievements.getAchievementsForProfile(member, req.language);
res.respond(200, achievsObject);
},
};
// Return a request handler for getMembersForGroup / getInvitesForGroup / getMembersForChallenge
// type is `invites` or `members`
function _getMembersForItem (type) {