Clone challenges api (#9684)

* Added clone api

* Added new clone UI

* Fixed challenge clone

* Fixed lint and added mongo toObject

* Removed clone field, fixed type, fixed challenge task query

* Auto selected group

* Accounted for group balance when creating challenge

* Added check for if user is leader of guild

* Added leader existence check

* Added fix for leader and prizecost equal to
This commit is contained in:
Keith Holliday
2018-01-30 08:23:20 -07:00
committed by GitHub
parent ccf8e0b320
commit 4fe6c8db64
5 changed files with 244 additions and 104 deletions

View File

@@ -1,6 +1,6 @@
<template lang="pug">
.row
challenge-modal(:cloning='cloning' v-on:updatedChallenge='updatedChallenge')
challenge-modal(v-on:updatedChallenge='updatedChallenge')
leave-challenge-modal(:challengeId='challenge._id')
close-challenge-modal(:members='members', :challengeId='challenge._id')
challenge-member-progress-modal(:memberId='progressMemberId', :challengeId='challenge._id')
@@ -220,7 +220,6 @@ export default {
memberIcon,
calendarIcon,
}),
cloning: false,
challenge: {},
members: [],
tasksByType: {
@@ -261,10 +260,6 @@ export default {
async beforeRouteUpdate (to, from, next) {
this.searchId = to.params.challengeId;
await this.loadChallenge();
if (this.$store.state.challengeOptions.cloning) {
this.cloneTasks(this.$store.state.challengeOptions.tasksToClone);
}
next();
},
methods: {
@@ -284,28 +279,6 @@ export default {
return cleansedTask;
},
cloneTasks (tasksToClone) {
let clonedTasks = [];
for (let key in tasksToClone) {
let tasksSection = tasksToClone[key];
tasksSection.forEach(task => {
let clonedTask = cloneDeep(task);
clonedTask = this.cleanUpTask(clonedTask);
clonedTask = taskDefaults(clonedTask);
this.tasksByType[task.type].push(clonedTask);
clonedTasks.push(clonedTask);
});
}
this.$store.dispatch('tasks:createChallengeTasks', {
challengeId: this.searchId,
tasks: clonedTasks,
});
this.$store.state.challengeOptions.cloning = false;
this.$store.state.challengeOptions.tasksToClone = [];
},
async loadChallenge () {
this.challenge = await this.$store.dispatch('challenges:getChallenge', {challengeId: this.searchId});
this.members = await this.$store.dispatch('members:getChallengeMembers', {challengeId: this.searchId});
@@ -377,7 +350,6 @@ export default {
},
edit () {
// @TODO: set working challenge
this.cloning = false;
this.$store.state.challengeOptions.workingChallenge = Object.assign({}, this.$store.state.challengeOptions.workingChallenge, this.challenge);
this.$root.$emit('bv::show::modal', 'challenge-modal');
},
@@ -396,10 +368,9 @@ export default {
window.location = `/api/v3/challenges/${this.searchId}/export/csv`;
},
cloneChallenge () {
this.cloning = true;
this.$store.state.challengeOptions.tasksToClone = this.tasksByType;
this.$store.state.challengeOptions.workingChallenge = Object.assign({}, this.$store.state.challengeOptions.workingChallenge, this.challenge);
this.$root.$emit('bv::show::modal', 'challenge-modal');
this.$root.$emit('habitica:clone-challenge', {
challenge: this.challenge,
});
},
},
};

View File

@@ -138,7 +138,7 @@ import { TAVERN_ID, MIN_SHORTNAME_SIZE_FOR_CHALLENGES, MAX_SUMMARY_SIZE_FOR_CHAL
import { mapState } from 'client/libs/store';
export default {
props: ['groupId', 'cloning'],
props: ['groupId'],
directives: {
markdown: markdownDirective,
},
@@ -224,6 +224,8 @@ export default {
shortName: '',
todos: [],
},
cloning: false,
cloningChallengeId: '',
showCategorySelect: false,
categoryOptions,
categoriesHashByKey,
@@ -231,7 +233,18 @@ export default {
groups: [],
};
},
async mounted () {},
mounted () {
this.$root.$on('habitica:clone-challenge', (data) => {
if (!data.challenge) return;
this.cloning = true;
this.cloningChallengeId = data.challenge._id;
this.$store.state.challengeOptions.workingChallenge = Object.assign({}, this.$store.state.challengeOptions.workingChallenge, data.challenge);
this.$root.$emit('bv::show::modal', 'challenge-modal');
});
},
destroyed () {
this.$root.$off('habitica:clone-challenge');
},
watch: {
user () {
if (!this.challenge) this.workingChallenge.leader = this.user._id;
@@ -252,7 +265,6 @@ export default {
if (this.creating) {
return this.$t('createChallenge');
}
return this.$t('editingChallenge');
},
charactersRemaining () {
@@ -322,6 +334,8 @@ export default {
if (!this.challenge) return;
this.workingChallenge = Object.assign({}, this.workingChallenge, this.challenge);
// @TODO: Should we use a separate field? I think the API expects `group` but it is confusing
this.workingChallenge.group = this.workingChallenge.group._id;
this.workingChallenge.categories = [];
if (this.challenge.categories) {
@@ -388,15 +402,40 @@ export default {
let challengeDetails = clone(this.workingChallenge);
challengeDetails.categories = serverCategories;
let challenge = await this.$store.dispatch('challenges:createChallenge', {challenge: challengeDetails});
// @TODO: When to remove from guild instead?
this.user.balance -= this.workingChallenge.prize / 4;
let challenge;
if (this.cloning) {
challenge = await this.$store.dispatch('challenges:cloneChallenge', {
challenge: challengeDetails,
cloningChallengeId: this.cloningChallengeId,
});
this.cloningChallengeId = '';
} else {
challenge = await this.$store.dispatch('challenges:createChallenge', {challenge: challengeDetails});
}
// Update Group Prize
let challengeGroup = this.groups.find(group => {
return group._id === this.workingChallenge.group;
});
// @TODO: Share with server
const prizeCost = this.workingChallenge.prize / 4;
const challengeGroupLeader = challengeGroup.leader && challengeGroup.leader._id ? challengeGroup.leader._id : challengeGroup.leader;
const userIsLeader = challengeGroupLeader === this.user._id;
if (challengeGroup && userIsLeader && challengeGroup.balance > 0 && challengeGroup.balance >= prizeCost) {
// Group pays for all of prize
} else if (challengeGroup && userIsLeader && challengeGroup.balance > 0) {
// User pays remainder of prize cost after group
let remainder = prizeCost - challengeGroup.balance;
this.user.balance -= remainder;
} else {
// User pays for all of prize
this.user.balance -= prizeCost;
}
this.$emit('createChallenge', challenge);
this.resetWorkingChallenge();
if (this.cloning) this.$store.state.challengeOptions.cloning = true;
this.$root.$emit('bv::hide::modal', 'challenge-modal');
this.$router.push(`/challenges/${challenge._id}`);
},