diff --git a/website/client/assets/svg/difficulty-star.svg b/website/client/assets/svg/difficulty-star.svg
new file mode 100644
index 0000000000..9409886974
--- /dev/null
+++ b/website/client/assets/svg/difficulty-star.svg
@@ -0,0 +1,3 @@
+
diff --git a/website/client/assets/svg/down.svg b/website/client/assets/svg/down.svg
new file mode 100644
index 0000000000..4d99b85f69
--- /dev/null
+++ b/website/client/assets/svg/down.svg
@@ -0,0 +1,3 @@
+
diff --git a/website/client/assets/svg/facebook.svg b/website/client/assets/svg/facebook.svg
new file mode 100644
index 0000000000..314d9515ad
--- /dev/null
+++ b/website/client/assets/svg/facebook.svg
@@ -0,0 +1,3 @@
+
diff --git a/website/client/assets/svg/message.svg b/website/client/assets/svg/message.svg
new file mode 100644
index 0000000000..dfd7c12a9c
--- /dev/null
+++ b/website/client/assets/svg/message.svg
@@ -0,0 +1,3 @@
+
diff --git a/website/client/assets/svg/qrCode.svg b/website/client/assets/svg/qrCode.svg
new file mode 100644
index 0000000000..7d1ea3e9f5
--- /dev/null
+++ b/website/client/assets/svg/qrCode.svg
@@ -0,0 +1,3 @@
+
diff --git a/website/client/assets/svg/quest-background-border.svg b/website/client/assets/svg/quest-background-border.svg
new file mode 100644
index 0000000000..81ae0b5bb3
--- /dev/null
+++ b/website/client/assets/svg/quest-background-border.svg
@@ -0,0 +1,36 @@
+
diff --git a/website/client/assets/svg/quest.svg b/website/client/assets/svg/quest.svg
new file mode 100644
index 0000000000..90ccf6ff77
--- /dev/null
+++ b/website/client/assets/svg/quest.svg
@@ -0,0 +1,3 @@
+
diff --git a/website/client/assets/svg/remove.svg b/website/client/assets/svg/remove.svg
new file mode 100644
index 0000000000..a717d49915
--- /dev/null
+++ b/website/client/assets/svg/remove.svg
@@ -0,0 +1,3 @@
+
diff --git a/website/client/assets/svg/star.svg b/website/client/assets/svg/star.svg
new file mode 100644
index 0000000000..8728bfb3ca
--- /dev/null
+++ b/website/client/assets/svg/star.svg
@@ -0,0 +1,10 @@
+
diff --git a/website/client/assets/svg/twitter.svg b/website/client/assets/svg/twitter.svg
new file mode 100644
index 0000000000..3606bb754b
--- /dev/null
+++ b/website/client/assets/svg/twitter.svg
@@ -0,0 +1,3 @@
+
diff --git a/website/client/assets/svg/up.svg b/website/client/assets/svg/up.svg
new file mode 100644
index 0000000000..047b91b7f7
--- /dev/null
+++ b/website/client/assets/svg/up.svg
@@ -0,0 +1,3 @@
+
diff --git a/website/client/components/appHeader.vue b/website/client/components/appHeader.vue
index cc66416dd2..21e7f631bf 100644
--- a/website/client/components/appHeader.vue
+++ b/website/client/components/appHeader.vue
@@ -59,15 +59,30 @@
.no-party {
.small-text {
color: $header-color;
+ flex-wrap: nowrap;
}
- h3 {
- color: $white;
- margin-bottom: 4px;
+ .no-party, .party-members {
+ flex-grow: 1;
}
- button {
- margin-top: 16px;
+ .party-members {
+ overflow-x: auto;
+ }
+
+ .no-party {
+ .small-text {
+ color: $header-color;
+ }
+
+ h3 {
+ color: $white;
+ margin-bottom: 4px;
+ }
+
+ button {
+ margin-top: 16px;
+ }
}
}
@@ -75,10 +90,12 @@
diff --git a/website/client/components/guilds/groupFormModal.vue b/website/client/components/guilds/groupFormModal.vue
index 5d434f0e3b..d023aaa917 100644
--- a/website/client/components/guilds/groupFormModal.vue
+++ b/website/client/components/guilds/groupFormModal.vue
@@ -1,10 +1,10 @@
- b-modal#guild-form(:title="title", :hide-footer="true")
+ b-modal#guild-form(:title="title", :hide-footer="true", size='lg')
form(@submit.stop.prevent="submit")
.form-group
label
strong(v-once) {{$t('name')}}*
- b-form-input(type="text", placeholder="$t('newGuildPlaceHolder')", v-model="newGuild.name")
+ b-form-input(type="text", :placeholder="$t('newGuildPlaceHolder')", v-model="newGuild.name")
.form-group(v-if='newGuild.id')
label
@@ -29,7 +29,7 @@
span.custom-control-description(v-once) {{ $t('guildLeaderCantBeMessaged') }}
br
- label.custom-control.custom-checkbox
+ label.custom-control.custom-checkbox(v-if='!creatingParty')
input.custom-control-input(type="checkbox", v-model="newGuild.privateGuild")
span.custom-control-indicator
span.custom-control-description(v-once) {{ $t('privateGuild') }}
@@ -37,7 +37,7 @@
.svg-icon(v-html='icons.information')
br
- label.custom-control.custom-checkbox
+ label.custom-control.custom-checkbox(v-if='!creatingParty')
input.custom-control-input(type="checkbox", v-model="newGuild.allowGuildInvationsFromNonMembers")
span.custom-control-indicator
span.custom-control-description(v-once) {{ $t('allowGuildInvationsFromNonMembers') }}
@@ -46,14 +46,18 @@
label
strong(v-once) {{$t('description')}}*
div.description-count {{charactersRemaining}} {{ $t('charactersRemaining') }}
- b-form-input(type="text", textarea :placeholder="$t('guildDescriptionPlaceHolder')", v-model="newGuild.description")
+ b-form-input(type="text", textarea :placeholder="creatingParty ? $t('partyDescriptionPlaceHolder') : $t('guildDescriptionPlaceHolder')", v-model="newGuild.description")
- .form-group(v-if='newGuild.id')
+ .form-group(v-if='newGuild.id && !creatingParty')
label
strong(v-once) {{$t('guildInformation')}}*
- b-form-input(type="text", textarea :placeholder="$t('guildInformationPlaceHolder')", v-model="newGuild.guildInformation")
+ b-form-input(type="text", textarea, :placeholder="$t('guildInformationPlaceHolder')", v-model="newGuild.guildInformation")
- .form-group(style='position: relative;')
+ .form-group(v-if='creatingParty && !newGuild.id')
+ span
+ toggleSwitch(:label="$t('inviteMembersNow')", v-model='inviteMembers')
+
+ .form-group(style='position: relative;', v-if='!creatingParty')
label
strong(v-once) {{$t('categories')}}*
div.category-wrap(@click.prevent="toggleCategorySelect")
@@ -70,13 +74,26 @@
span.custom-control-description(v-once) {{ $t(group.label) }}
button.btn.btn-primary(@click.prevent="toggleCategorySelect") {{$t('close')}}
+ .form-group(v-if='inviteMembers && !newGuild.id')
+ label
+ strong(v-once) Invite via Email or User ID
+ p Invite users via a valid email or 36-digit User ID. If an email isn’t registered yet, we’ll invite them to join.
+
+ div
+ div(v-for='(member, index) in membersToInvite')
+ input(type='text', v-model='member.value')
+ button(@click.prevent='removeMemberToInvite(index)') Remove
+ div
+ input(type='text', placeholder='Email address or User ID', v-model='newMemberToInvite.value')
+ button(@click.prevent='addMemberToInvite()') Add
+
.form-group.text-center
- div.item-with-icon
+ div.item-with-icon(v-if='!creatingParty')
.svg-icon(v-html="icons.gem")
span.count 4
- button.btn.btn-primary.btn-md(v-if='!newGuild.id', :disabled='!newGuild.name || !newGuild.description') {{ $t('createGuild') }}
- button.btn.btn-primary.btn-md(v-if='newGuild.id', :disabled='!newGuild.name || !newGuild.description') {{ $t('updateGuild') }}
- .gem-description(v-once) {{ $t('guildGemCostInfo') }}
+ button.btn.btn-primary.btn-md(v-if='!newGuild.id', :disabled='!newGuild.name || !newGuild.description') {{ creatingParty ? $t('createParty') : $t('createGuild') }}
+ button.btn.btn-primary.btn-md(v-if='newGuild.id', :disabled='!newGuild.name || !newGuild.description') {{ creatingParty ? $t('updateParty') : $t('updateGuild') }}
+ .gem-description(v-once, v-if='!creatingParty') {{ $t('guildGemCostInfo') }}
diff --git a/website/client/components/guilds/membersModal.vue b/website/client/components/guilds/membersModal.vue
index 106a5698f6..274d84cdf7 100644
--- a/website/client/components/guilds/membersModal.vue
+++ b/website/client/components/guilds/membersModal.vue
@@ -1,6 +1,9 @@
div
- button.btn.btn-primary(b-btn, @click="$root.$emit('show::modal','members-modal')") {{ $t('viewMembers') }}
+ .item-with-icon(@click="$root.$emit('show::modal','members-modal')")
+ .svg-icon.shield(v-html="icons.goldGuildBadgeIcon")
+ span.number {{group.memberCount}}
+ div(v-once) {{ $t('members') }}
b-modal#members-modal(:title="$t('createGuild')", size='lg')
.header-wrap(slot="modal-header")
@@ -19,24 +22,25 @@ div
b-dropdown-item(v-for='sortOption in sortOptions', @click='sort(sortOption.value)', :key='sortOption.value') {{sortOption.text}}
.row(v-for='member in members', :key='member', )
.col-8.offset-1
- member-details(:user='member')
+ member-details(:member='member')
.col-3.actions
b-dropdown(:text="$t('sort')", right=true)
b-dropdown-item(@click='sort(option.value)')
- img.action-icon(src='~assets/members/remove.svg')
+ .svg-icon(v-html="icons.removeIcon")
| {{$t('removeMember')}}
b-dropdown-item(@click='sort(option.value)')
- img.action-icon(src='~assets/members/message.svg')
+ .svg-icon(v-html="icons.messageIcon")
| {{$t('sendMessage')}}
b-dropdown-item(@click='sort(option.value)')
- img.action-icon(src='~assets/members/star.svg')
+ .svg-icon(v-html="icons.starIcon")
| {{$t('promoteToLeader')}}
b-dropdown-item(@click='sort(option.value)')
- img.action-icon(src='~assets/members/star.svg')
+ .svg-icon(v-html="icons.starIcon")
| {{$t('addManager')}}
b-dropdown-item(@click='sort(option.value)')
- img.action-icon(src='~assets/members/remove.svg')
+ .svg-icon(v-html="icons.removeIcon")
| {{$t('removeManager2')}}
+ .row-fluid.gradient
b-modal#remove-member(:title="$t('confirmRemoveMember')")
button(@click='confirmRemoveMember(member)', v-once) {{$t('remove')}}
@@ -45,7 +49,7 @@ div
button(@click='confirmRemoveMember(member)', v-once) {{$t('remove')}}
-
diff --git a/website/client/components/guilds/startQuestModal.vue b/website/client/components/guilds/startQuestModal.vue
new file mode 100644
index 0000000000..14834a3b32
--- /dev/null
+++ b/website/client/components/guilds/startQuestModal.vue
@@ -0,0 +1,156 @@
+
+ b-modal#start-quest-modal(title="Empty", size='md', hide-footer=true, v-if='questData')
+ .quest-image(:class="'quest_' + questData.key")
+ h2 {{questData.text()}}
+ //- span by: Keith Holliday @TODO: Add author
+ p {{questData.notes()}}
+ div.quest-details
+ div(v-if=' questData.collect')
+ Strong {{$t('collect')}}:
+ span(v-for="(value, key, index) in questData.collect")
+ | {{$t('collectionItems', { number: questData.collect[key].count, items: questData.collect[key].text() })}}
+ div
+ Strong {{$t('collect')}}:
+ span
+ .svg-icon(v-html="icons.difficultyStarIcon")
+ div
+ button.btn.btn-primary(@click='questInit()') {{$t('inviteToPartyOrQuest')}}
+ div
+ p {{$t('inviteInformation')}}
+ .side-panel
+ h4.text-center {{$t('rewards')}}
+ .box
+ .svg-icon.rewards-icon(v-html="icons.starIcon")
+ strong {{questData.drop.exp}} {{$t('experience')}}
+ .box
+ .svg-icon.rewards-icon(v-html="icons.goldIcon")
+ strong {{questData.drop.gp}} {{$t('gold')}}
+ h4.text-center(v-if='questData.drop.items') {{$t('questOwnerRewards')}}
+ .box(v-for='item in questData.drop.items')
+ .rewards-icon(v-if='item.type === "quest"', :class="'quest_' + item.key")
+ .drop-rewards-icon(v-if='item.type === "gear"', :class="'shop_' + item.key")
+ strong.quest-reward-text {{item.text()}}
+
+
+
+
+
diff --git a/website/client/components/ui/toggleSwitch.vue b/website/client/components/ui/toggleSwitch.vue
index d1eda4074b..779f296aa3 100644
--- a/website/client/components/ui/toggleSwitch.vue
+++ b/website/client/components/ui/toggleSwitch.vue
@@ -4,8 +4,9 @@
.toggle-switch.float-left
input.toggle-switch-checkbox(
type='checkbox', :id="id",
- @change="$emit('change', $event.target.checked)",
- :checked="checked",
+ @change="handleChange",
+ :checked="isChecked",
+ :value="value",
)
label.toggle-switch-label(:for="id")
span.toggle-switch-inner
@@ -13,88 +14,88 @@
diff --git a/website/client/router.js b/website/client/router.js
index 1065f5b65a..93f9a7364e 100644
--- a/website/client/router.js
+++ b/website/client/router.js
@@ -28,7 +28,7 @@ const InboxConversationPage = () => import(/* webpackChunkName: "inbox" */ './co
// Guilds
const GuildIndex = () => import(/* webpackChunkName: "guilds" */ './components/guilds/index');
-const TavernPage = () => import(/* webpackChunkName: "guilds" */ './components/guilds/tavern');
+// const TavernPage = () => import(/* webpackChunkName: "guilds" */ './components/guilds/tavern');
const MyGuilds = () => import(/* webpackChunkName: "guilds" */ './components/guilds/myGuilds');
const GuildsDiscoveryPage = () => import(/* webpackChunkName: "guilds" */ './components/guilds/discovery');
const GuildPage = () => import(/* webpackChunkName: "guilds" */ './components/guilds/guild');
@@ -56,11 +56,12 @@ export default new VueRouter({
],
},
{ name: 'shops', path: '/shops', component: Page },
+ { name: 'party', path: '/party', component: GuildPage },
{
path: '/guilds',
component: GuildIndex,
children: [
- { name: 'tavern', path: 'tavern', component: TavernPage },
+ { name: 'tavern', path: 'tavern', component: GuildPage },
{
name: 'myGuilds',
path: 'myGuilds',
@@ -80,7 +81,6 @@ export default new VueRouter({
],
},
{ name: 'challenges', path: 'challenges', component: Page },
- { name: 'party', path: 'party', component: Page },
{
path: '/user',
component: ParentPage,
diff --git a/website/client/store/actions/index.js b/website/client/store/actions/index.js
index 965e9041a3..d86a04db6c 100644
--- a/website/client/store/actions/index.js
+++ b/website/client/store/actions/index.js
@@ -6,6 +6,7 @@ import * as tasks from './tasks';
import * as guilds from './guilds';
import * as party from './party';
import * as members from './members';
+import * as quests from './quests';
// Actions should be named as 'actionName' and can be accessed as 'namespace:actionName'
// Example: fetch in user.js -> 'user:fetch'
@@ -17,6 +18,7 @@ const actions = flattenAndNamespace({
guilds,
party,
members,
+ quests,
});
export default actions;
diff --git a/website/client/store/actions/quests.js b/website/client/store/actions/quests.js
new file mode 100644
index 0000000000..5ad1281e09
--- /dev/null
+++ b/website/client/store/actions/quests.js
@@ -0,0 +1,16 @@
+import axios from 'axios';
+// export async function initQuest (store) {
+// }
+
+export async function sendAction (store, payload) {
+ // Analytics.updateUser({
+ // partyID: party._id,
+ // partySize: party.memberCount
+ // });
+ let response = await axios.post(`/api/v3/groups/${payload.groupId}/${payload.action}`);
+
+ // @TODO: Update user?
+ // User.sync();
+
+ return response.data.quest || response.data.data;
+}
diff --git a/website/client/store/index.js b/website/client/store/index.js
index bb5597514f..fee62bf38c 100644
--- a/website/client/store/index.js
+++ b/website/client/store/index.js
@@ -18,6 +18,7 @@ export default function () {
user: asyncResourceFactory(),
tasks: asyncResourceFactory(), // user tasks
party: {
+ quest: {},
members: asyncResourceFactory(),
},
myGuilds: [],
diff --git a/website/common/locales/en/newClient.json b/website/common/locales/en/newClient.json
index 81e710db12..7605789369 100644
--- a/website/common/locales/en/newClient.json
+++ b/website/common/locales/en/newClient.json
@@ -71,8 +71,8 @@
"silverTier": "Silver Tier",
"bronzeTier": "Bronze Tier",
"privacySettings": "Privacy Settings",
- "onlyLeaderCreatesChallenges": "Only the Guild Leader can create Guild Challenges",
- "guildLeaderCantBeMessaged": "Guild Leader can not be messaged directly",
+ "onlyLeaderCreatesChallenges": "Only the Leader can create Challenges",
+ "guildLeaderCantBeMessaged": "Leader can not be messaged directly",
"privateGuild": "Private Guild",
"allowGuildInvationsFromNonMembers": "Allow Guild invitations from non-members",
"charactersRemaining": "characters remaining",
@@ -88,6 +88,30 @@
"removeManager2": "Remove Manager",
"promoteToLeader": "Promote to Leader",
"inviteFriendsParty": "Inviting friends to your party will grant you an exclusive
Quest Scroll to battle the Basi-List together!",
+ "upgradeParty": "Upgrade Party",
+ "questDetailsTitle": "Quest Details",
+ "yourNotOnQuest": "You're not on a quest",
+ "questDescription": "Quests allow players to focus on long-term, in-game goals with the members of their party.",
+ "haveNoChallenges": "You don’t have any Challenges",
+ "challengeDescription": "Challenges are community events in which players compete and earn prizes by completing a group of related tasks.",
+ "createParty": "Create a Party",
+ "partyDescriptionPlaceHolder": "This is our party’s description. It describes what we do in this party. If you want to learn more about what we do in this party, read the description. Party on.",
+ "inviteMembersNow": "Would you like to invite users now?",
+ "playInPartyTitle": "Play Habitica in a Party!",
+ "playInPartyDescription": "Take on amazing quests with friends or on your own. Battle monsters, create Challenges, and help yourself stay accountable through Parties.",
+ "startYourOwnPartyTitle": "Start your own Party",
+ "startYourOwnPartyDescription": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam accumsan sagittis tellus tempor euismod. Sed imperdiet facilisis tortor in malesuada.",
+ "shartUserId": "Share User ID",
+ "wantToJoinPartyTitle": "Want to join a Party?",
+ "wantToJoinPartyDescription": "Aenean non mattis eros, quis semper ipsum. Phasellus vulputate in nibh et suscipit. In hac habitasse platea dictumst.",
+ "copy": "Copy",
+ "lookingForGroup": "Looking for Group",
+ "inviteToPartyOrQuest": "Invite Party to Quest",
+ "inviteInformation": "Clicking “Invite” will send an invitation to your party members. When all members have accepted or denied, the Quest begins.",
+ "questOwnerRewards": "Quest Owner Rewards",
+ "guildInformationPlaceHolder": "This is our party’s description. It describes what we do in this party. If you want to learn more about what we do in this party, read the description. Party on.",
+ "updateParty": "Update Party",
+ "upgrade": "Upgrade",
"showAllAnimals": "Show All <%= color %> <%= type %>",
"showLessAnimals": "Show Less <%= color %> <%= type %>",
"quickInventory": "Quick Inventory",