2017-06-02 20:55:02 +00:00
< template lang = "pug" >
2017-06-27 20:02:55 +00:00
b - modal # guild - form ( : title = "title" , : hide - footer = "true" , size = 'lg' )
2017-06-02 20:55:02 +00:00
form ( @ submit . stop . prevent = "submit" )
. form - group
label
2017-08-21 15:36:31 +00:00
strong ( v - once ) { { $t ( 'name' ) } } *
2017-08-23 03:58:13 +00:00
b - form - input ( type = "text" , : placeholder = "$t('newGuildPlaceholder')" , v - model = "workingGroup.name" )
. form - group ( v - if = 'workingGroup.id && members.length > 0' )
2017-06-02 20:55:02 +00:00
label
2017-08-22 20:39:45 +00:00
strong ( v - once ) { { $t ( 'guildOrPartyLeader' ) } } *
2017-08-23 03:58:13 +00:00
select . form - control ( v - model = "workingGroup.newLeader" )
2017-07-29 22:08:36 +00:00
option ( v - for = 'member in members' , : value = "member._id" ) { { member . profile . name } }
2017-06-02 20:55:02 +00:00
. form - group
label
2017-08-22 20:39:45 +00:00
strong ( v - once ) { { $t ( 'privacySettings' ) } } *
2017-06-02 20:55:02 +00:00
br
label . custom - control . custom - checkbox
2017-08-23 03:58:13 +00:00
input . custom - control - input ( type = "checkbox" , v - model = "workingGroup.onlyLeaderCreatesChallenges" )
2017-06-02 20:55:02 +00:00
span . custom - control - indicator
span . custom - control - description ( v - once ) { { $t ( 'onlyLeaderCreatesChallenges' ) } }
b - tooltip . icon ( : content = "$t('privateDescription')" )
2017-06-08 19:04:19 +00:00
. svg - icon ( v - html = 'icons.information' )
2017-06-02 20:55:02 +00:00
2017-07-31 19:54:52 +00:00
// br
// @TODO Implement in V2 label.custom-control.custom-checkbox
2017-08-23 03:58:13 +00:00
input . custom - control - input ( type = "checkbox" , v - model = "workingGroup.guildLeaderCantBeMessaged" )
2017-06-02 20:55:02 +00:00
span . custom - control - indicator
span . custom - control - description ( v - once ) { { $t ( 'guildLeaderCantBeMessaged' ) } }
2017-08-26 16:53:10 +00:00
// "guildLeaderCantBeMessaged": "Leader can not be messaged directly",
// @TODO discuss the impact of this with moderators before implementing
2017-06-02 20:55:02 +00:00
br
2017-08-21 15:36:31 +00:00
label . custom - control . custom - checkbox ( v - if = '!isParty' )
2017-08-23 03:58:13 +00:00
input . custom - control - input ( type = "checkbox" , v - model = "workingGroup.privateGuild" )
2017-06-02 20:55:02 +00:00
span . custom - control - indicator
span . custom - control - description ( v - once ) { { $t ( 'privateGuild' ) } }
b - tooltip . icon ( : content = "$t('privateDescription')" )
2017-06-08 19:04:19 +00:00
. svg - icon ( v - html = 'icons.information' )
2017-06-02 20:55:02 +00:00
2017-07-31 19:54:52 +00:00
// br
// @TODO: Implement in v2 label.custom-control.custom-checkbox(v-if='!creatingParty')
2017-08-26 16:53:10 +00:00
input . custom - control - input ( type = "checkbox" , v - model = "workingGroup.allowGuildInvitationsFromNonMembers" )
2017-06-02 20:55:02 +00:00
span . custom - control - indicator
2017-08-26 16:53:10 +00:00
span . custom - control - description ( v - once ) { { $t ( 'allowGuildInvitationsFromNonMembers' ) } }
// "allowGuildInvitationsFromNonMembers": "Allow Guild invitations from non-members",
2017-06-02 20:55:02 +00:00
2017-08-22 20:39:45 +00:00
. form - group ( v - if = '!creatingParty' )
2017-06-02 20:55:02 +00:00
label
2017-08-22 20:39:45 +00:00
strong ( v - once ) { { $t ( 'guildSummary' ) } } *
div . summary - count { { charactersRemaining } } { { $t ( 'charactersRemaining' ) } }
2017-08-23 03:58:13 +00:00
textarea . form - control . summary - textarea ( : placeholder = "isParty ? $t('partyDescriptionPlaceHolder') : $t('guildSummaryPlaceholder')" , v - model = "workingGroup.summary" )
2017-08-22 20:39:45 +00:00
// @TODO: need summary only for PUBLIC GUILDS, not for tavern, private guilds, or party
2017-06-02 20:55:02 +00:00
2017-08-22 20:39:45 +00:00
. form - group
2017-06-02 20:55:02 +00:00
label
2017-08-22 20:39:45 +00:00
strong ( v - once ) { { $t ( 'groupDescription' ) } } *
a . float - right { { $t ( 'markdownFormattingHelp' ) } }
2017-08-23 03:58:13 +00:00
b - form - input . description - textarea ( type = "text" , textarea , : placeholder = "isParty ? $t('partyDescriptionPlaceholder') : $t('guildDescriptionPlaceholder')" , v - model = "workingGroup.description" )
2017-06-02 20:55:02 +00:00
2017-08-23 03:58:13 +00:00
. form - group ( v - if = 'creatingParty && !workingGroup.id' )
2017-06-27 20:02:55 +00:00
span
toggleSwitch ( : label = "$t('inviteMembersNow')" , v - model = 'inviteMembers' )
2017-08-21 15:36:31 +00:00
. form - group ( style = 'position: relative;' , v - if = '!creatingParty && !isParty' )
2017-06-02 20:55:02 +00:00
label
2017-08-22 20:39:45 +00:00
strong ( v - once ) { { $t ( 'categories' ) } } *
2017-06-02 20:55:02 +00:00
div . category - wrap ( @ click . prevent = "toggleCategorySelect" )
2017-08-23 03:58:13 +00:00
span . category - select ( v - if = 'workingGroup.categories.length === 0' ) { { $t ( 'none' ) } }
. category - label ( v - for = 'category in workingGroup.categories' ) { { $t ( categoriesHashByKey [ category ] ) } }
2017-06-02 20:55:02 +00:00
. category - box ( v - if = "showCategorySelect" )
. form - check (
v - for = "group in categoryOptions" ,
: key = "group.key" ,
)
label . custom - control . custom - checkbox
2017-08-23 03:58:13 +00:00
input . custom - control - input ( type = "checkbox" , : value = "group.key" , v - model = "workingGroup.categories" )
2017-06-02 20:55:02 +00:00
span . custom - control - indicator
span . custom - control - description ( v - once ) { { $t ( group . label ) } }
button . btn . btn - primary ( @ click . prevent = "toggleCategorySelect" ) { { $t ( 'close' ) } }
2017-08-22 20:39:45 +00:00
// @TODO: need categories only for PUBLIC GUILDS, not for tavern, private guilds, or party
2017-06-02 20:55:02 +00:00
2017-08-23 03:58:13 +00:00
. form - group ( v - if = 'inviteMembers && !workingGroup.id' )
2017-06-27 20:02:55 +00:00
label
strong ( v - once ) Invite via Email or User ID
2017-08-22 20:39:45 +00:00
p ( v - once ) { { $t ( 'inviteMembersHowTo' ) } } *
2017-06-27 20:02:55 +00:00
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
2017-06-02 20:55:02 +00:00
. form - group . text - center
2017-08-23 03:58:13 +00:00
div . item - with - icon ( v - if = '!this.workingGroup.id' )
2017-06-08 19:04:19 +00:00
. svg - icon ( v - html = "icons.gem" )
2017-06-02 20:55:02 +00:00
span . count 4
2017-08-23 03:58:13 +00:00
button . btn . btn - primary . btn - md ( v - if = '!workingGroup.id' , : disabled = '!workingGroup.name || !workingGroup.description' ) { { creatingParty ? $t ( 'createParty' ) : $t ( 'createGuild' ) } }
button . btn . btn - primary . btn - md ( v - if = 'workingGroup.id' , : disabled = '!workingGroup.name || !workingGroup.description' ) { { isParty ? $t ( 'updateParty' ) : $t ( 'updateGuild' ) } }
. gem - description ( v - once , v - if = '!this.workingGroup.id' ) { { $t ( 'guildGemCostInfo' ) } }
2017-06-02 20:55:02 +00:00
< / template >
2017-06-08 19:04:19 +00:00
< style lang = "scss" scoped >
@ import '~client/assets/scss/colors.scss' ;
2017-08-18 20:29:49 +00:00
. svg - icon {
width : 16 px ;
}
2017-06-02 20:55:02 +00:00
textarea {
height : 150 px ;
}
2017-06-08 19:04:19 +00:00
2017-08-22 20:39:45 +00:00
. summary - count , . gem - description {
2017-06-02 20:55:02 +00:00
font - size : 12 px ;
line - height : 1.33 ;
2017-08-22 20:39:45 +00:00
margin - top : 1 em ;
2017-06-02 20:55:02 +00:00
color : $gray - 200 ;
}
2017-08-22 20:39:45 +00:00
. summary - count {
2017-06-02 20:55:02 +00:00
text - align : right ;
}
. gem - description {
2017-08-22 20:39:45 +00:00
text - align : center ;
}
. summary - textarea {
height : 90 px ;
}
. description - textarea {
height : 220 px ;
2017-06-02 20:55:02 +00:00
}
. item - with - icon {
display : inline - block ;
img {
height : 20 px ;
margin - right : .5 em ;
}
. count {
font - size : 14 px ;
font - weight : bold ;
margin - right : 1 em ;
color : $green - 10 ;
}
}
. icon {
margin - left : .5 em ;
display : inline - block ;
}
< / style >
< script >
import bModal from 'bootstrap-vue/lib/components/modal' ;
import bBtn from 'bootstrap-vue/lib/components/button' ;
import bFormInput from 'bootstrap-vue/lib/components/form-input' ;
import bFormCheckbox from 'bootstrap-vue/lib/components/form-checkbox' ;
import bFormSelect from 'bootstrap-vue/lib/components/form-select' ;
import bTooltip from 'bootstrap-vue/lib/components/tooltip' ;
2017-06-27 20:02:55 +00:00
import toggleSwitch from 'client/components/ui/toggleSwitch' ;
2017-06-08 19:04:19 +00:00
import gemIcon from 'assets/svg/gem.svg' ;
import informationIcon from 'assets/svg/information.svg' ;
2017-08-22 20:39:45 +00:00
import { MAX _SUMMARY _SIZE _FOR _GUILDS } from '../../../common/script/constants' ;
2017-07-31 19:54:52 +00:00
// @TODO: Not sure the best way to pass party creating status
// Since we need the modal in the header, passing props doesn't work
// because we can't import the create group in the index of groups
// I think state is the correct spot, but maybe we should separate into
// two modals?
2017-06-02 20:55:02 +00:00
export default {
components : {
bModal ,
bBtn ,
bFormInput ,
bFormCheckbox ,
bFormSelect ,
bTooltip ,
2017-06-27 20:02:55 +00:00
toggleSwitch ,
2017-06-02 20:55:02 +00:00
} ,
data ( ) {
let data = {
2017-08-23 03:58:13 +00:00
workingGroup : {
2017-06-02 20:55:02 +00:00
id : '' ,
name : '' ,
type : 'guild' ,
privacy : 'private' ,
2017-08-22 20:39:45 +00:00
summary : '' ,
2017-06-02 20:55:02 +00:00
description : '' ,
categories : [ ] ,
onlyLeaderCreatesChallenges : true ,
guildLeaderCantBeMessaged : true ,
privateGuild : true ,
2017-08-26 16:53:10 +00:00
allowGuildInvitationsFromNonMembers : true ,
2017-06-02 20:55:02 +00:00
newLeader : '' ,
} ,
categoryOptions : [
{
2017-08-09 16:56:48 +00:00
label : 'habitica_official' ,
key : 'habitica_official' ,
2017-06-02 20:55:02 +00:00
} ,
{
2017-08-09 16:56:48 +00:00
label : 'academics' ,
key : 'academics' ,
2017-06-02 20:55:02 +00:00
} ,
{
2017-08-09 16:56:48 +00:00
label : 'advocacy_causes' ,
key : 'advocacy_causes' ,
2017-06-02 20:55:02 +00:00
} ,
{
2017-08-09 16:56:48 +00:00
label : 'creativity' ,
key : 'creativity' ,
2017-06-02 20:55:02 +00:00
} ,
{
2017-08-09 16:56:48 +00:00
label : 'entertainment' ,
key : 'entertainment' ,
2017-06-02 20:55:02 +00:00
} ,
{
2017-08-09 16:56:48 +00:00
label : 'finance' ,
key : 'finance' ,
2017-06-02 20:55:02 +00:00
} ,
{
2017-08-09 16:56:48 +00:00
label : 'health_fitness' ,
key : 'health_fitness' ,
2017-06-02 20:55:02 +00:00
} ,
{
2017-08-09 16:56:48 +00:00
label : 'hobbies_occupations' ,
key : 'hobbies_occupations' ,
} ,
{
label : 'location_based' ,
key : 'location_based' ,
} ,
{
label : 'mental_health' ,
2017-08-16 20:03:07 +00:00
key : 'mental_health' ,
2017-08-09 16:56:48 +00:00
} ,
{
label : 'organization' ,
2017-08-16 20:03:07 +00:00
key : 'organization' ,
2017-06-02 20:55:02 +00:00
} ,
{
2017-08-16 20:03:07 +00:00
label : 'recovery_support_groups' ,
key : 'recovery_support_groups' ,
2017-06-02 20:55:02 +00:00
} ,
{
2017-08-09 16:56:48 +00:00
label : 'spirituality' ,
2017-08-16 20:03:07 +00:00
key : 'spirituality' ,
2017-06-02 20:55:02 +00:00
} ,
{
2017-08-09 16:56:48 +00:00
label : 'time_management' ,
key : 'time_management' ,
2017-06-02 20:55:02 +00:00
} ,
] ,
showCategorySelect : false ,
2017-07-29 22:08:36 +00:00
members : [ ] ,
2017-06-27 20:02:55 +00:00
inviteMembers : false ,
newMemberToInvite : {
value : '' ,
type : '' ,
} ,
membersToInvite : [ ] ,
2017-06-02 20:55:02 +00:00
} ;
let hashedCategories = { } ;
data . categoryOptions . forEach ( ( category ) => {
hashedCategories [ category . key ] = category . label ;
} ) ;
data . categoriesHashByKey = hashedCategories ;
2017-06-08 19:04:19 +00:00
data . icons = Object . freeze ( {
gem : gemIcon ,
information : informationIcon ,
} ) ;
2017-06-02 20:55:02 +00:00
return data ;
} ,
mounted ( ) {
2017-07-31 19:54:52 +00:00
// @TODO: do we need this? Maybe us computed. If we need, then make it on show a specific modal
2017-06-02 20:55:02 +00:00
this . $root . $on ( 'shown::modal' , ( ) => {
let editingGroup = this . $store . state . editingGroup ;
2017-08-23 03:58:13 +00:00
if ( ! editingGroup . _id ) {
this . resetWorkingGroup ( ) ;
return ;
}
this . workingGroup . name = editingGroup . name ;
this . workingGroup . type = editingGroup . type ;
this . workingGroup . privateGuild = true ;
if ( editingGroup . privacy === 'public' ) {
this . workingGroup . privateGuild = false ;
}
2017-08-29 20:23:09 +00:00
if ( editingGroup . categories ) {
editingGroup . categories . forEach ( category => {
this . workingGroup . categories . push ( category . slug ) ;
} ) ;
}
2017-08-23 03:58:13 +00:00
if ( editingGroup . summary ) this . workingGroup . summary = editingGroup . summary ;
if ( editingGroup . description ) this . workingGroup . description = editingGroup . description ;
if ( editingGroup . _id ) this . workingGroup . id = editingGroup . _id ;
if ( editingGroup . leader . _id ) this . workingGroup . newLeader = editingGroup . leader . _id ;
2017-07-31 19:54:52 +00:00
if ( editingGroup . _id ) this . getMembers ( ) ;
2017-06-02 20:55:02 +00:00
} ) ;
} ,
computed : {
charactersRemaining ( ) {
2017-08-23 03:58:13 +00:00
let currentLength = this . workingGroup . summary ? this . workingGroup . summary . length : 0 ;
2017-08-22 20:39:45 +00:00
return MAX _SUMMARY _SIZE _FOR _GUILDS - currentLength ;
2017-06-02 20:55:02 +00:00
} ,
title ( ) {
2017-06-27 20:02:55 +00:00
if ( this . creatingParty ) return this . $t ( 'createParty' ) ;
2017-08-23 03:58:13 +00:00
if ( ! this . workingGroup . id ) return this . $t ( 'createGuild' ) ;
2017-08-21 15:36:31 +00:00
if ( this . isParty ) return this . $t ( 'updateParty' ) ;
2017-06-02 20:55:02 +00:00
return this . $t ( 'updateGuild' ) ;
} ,
2017-07-31 19:54:52 +00:00
creatingParty ( ) {
return this . $store . state . groupFormOptions . createParty ;
} ,
2017-08-21 15:36:31 +00:00
isParty ( ) {
2017-08-23 03:58:13 +00:00
return this . workingGroup . type === 'party' ;
2017-08-21 15:36:31 +00:00
} ,
2017-06-02 20:55:02 +00:00
} ,
methods : {
2017-07-29 22:08:36 +00:00
async getMembers ( ) {
2017-08-23 03:58:13 +00:00
if ( ! this . workingGroup . id ) return ;
2017-07-29 22:08:36 +00:00
let members = await this . $store . dispatch ( 'members:getGroupMembers' , {
2017-08-23 03:58:13 +00:00
groupId : this . workingGroup . id ,
2017-07-29 22:08:36 +00:00
includeAllPublicFields : true ,
} ) ;
this . members = members ;
} ,
2017-06-27 20:02:55 +00:00
addMemberToInvite ( ) {
// @TODO: determine type
this . membersToInvite . push ( this . newMemberToInvite ) ;
this . newMemberToInvite = {
value : '' ,
type : '' ,
} ;
} ,
removeMemberToInvite ( index ) {
this . membersToInvite . splice ( index , 1 ) ;
} ,
2017-06-02 20:55:02 +00:00
toggleCategorySelect ( ) {
this . showCategorySelect = ! this . showCategorySelect ;
} ,
async submit ( ) {
2017-08-23 03:58:13 +00:00
if ( this . $store . state . user . data . balance < 1 && ! this . workingGroup . id ) {
2017-06-02 20:55:02 +00:00
// @TODO: Add proper notifications
alert ( 'Not enough gems' ) ;
return ;
// @TODO return $rootScope.openModal('buyGems', {track:"Gems > Create Group"});
}
2017-08-23 03:58:13 +00:00
if ( ! this . workingGroup . name || ! this . workingGroup . description ) {
2017-08-22 20:39:45 +00:00
// @TODO: Add proper notifications - split this out into two, make errors translatable. Suggestion: `<% fieldName %> is required` for all errors where possible, where `fieldName` is inserted as the translatable string that's used for the field header.
2017-06-02 20:55:02 +00:00
alert ( 'Enter a name and description' ) ;
return ;
}
2017-08-23 03:58:13 +00:00
if ( ! this . workingGroup . summary ) {
2017-08-22 20:39:45 +00:00
// @TODO: Add proper notifications. Summary is mandatory for only public guilds (not tavern, private guilds, parties)
alert ( 'Enter a summary' ) ;
return ;
}
2017-08-23 03:58:13 +00:00
if ( this . workingGroup . summary . length > MAX _SUMMARY _SIZE _FOR _GUILDS ) {
2017-08-22 20:39:45 +00:00
// @TODO: Add proper notifications. Summary is mandatory for only public guilds (not tavern, private guilds, parties)
alert ( 'Summary is too long' ) ;
return ;
}
2017-08-23 03:58:13 +00:00
if ( ! this . workingGroup . categories || this . workingGroup . categories . length === 0 ) {
2017-06-02 20:55:02 +00:00
// @TODO: Add proper notifications
2017-08-22 20:39:45 +00:00
alert ( 'One or more categories must be selected' ) ;
2017-06-02 20:55:02 +00:00
return ;
}
// @TODO: Add proper notifications
2017-08-23 03:58:13 +00:00
if ( ! this . workingGroup . id && ! confirm ( this . $t ( 'confirmGuild' ) ) ) return ;
2017-06-02 20:55:02 +00:00
2017-08-23 03:58:13 +00:00
if ( ! this . workingGroup . privateGuild ) {
this . workingGroup . privacy = 'public' ;
2017-06-02 20:55:02 +00:00
}
2017-08-23 03:58:13 +00:00
if ( ! this . workingGroup . onlyLeaderCreatesChallenges ) {
this . workingGroup . leaderOnly = {
2017-06-02 20:55:02 +00:00
challenges : true ,
} ;
}
2017-08-23 03:58:13 +00:00
let categoryKeys = this . workingGroup . categories ;
2017-08-18 20:29:49 +00:00
let serverCategories = [ ] ;
categoryKeys . forEach ( key => {
let catName = this . categoriesHashByKey [ key ] ;
serverCategories . push ( {
slug : key ,
name : catName ,
} ) ;
} ) ;
2017-08-23 03:58:13 +00:00
this . workingGroup . categories = serverCategories ;
2017-08-09 16:56:48 +00:00
2017-08-18 20:29:49 +00:00
let newgroup ;
2017-08-23 03:58:13 +00:00
if ( this . workingGroup . id ) {
await this . $store . dispatch ( 'guilds:update' , { group : this . workingGroup } ) ;
this . $root . $emit ( 'updatedGroup' , this . workingGroup ) ;
2017-07-29 22:08:36 +00:00
// @TODO: this doesn't work because of the async resource
// if (updatedGroup.type === 'party') this.$store.state.party = {data: updatedGroup};
2017-06-02 20:55:02 +00:00
} else {
2017-08-23 03:58:13 +00:00
newgroup = await this . $store . dispatch ( 'guilds:create' , { group : this . workingGroup } ) ;
2017-08-09 16:56:48 +00:00
this . $store . state . user . data . balance -= 1 ;
2017-06-02 20:55:02 +00:00
}
this . $store . state . editingGroup = { } ;
2017-08-23 03:58:13 +00:00
this . workingGroup = {
2017-06-02 20:55:02 +00:00
name : '' ,
type : 'guild' ,
privacy : 'private' ,
description : '' ,
categories : [ ] ,
onlyLeaderCreatesChallenges : true ,
guildLeaderCantBeMessaged : true ,
privateGuild : true ,
2017-08-26 16:53:10 +00:00
allowGuildInvitationsFromNonMembers : true ,
2017-06-02 20:55:02 +00:00
} ;
2017-06-27 20:02:55 +00:00
2017-08-09 16:56:48 +00:00
if ( newgroup && newgroup . _id ) {
this . $router . push ( ` /groups/guild/ ${ newgroup . _id } ` ) ;
}
2017-06-27 20:02:55 +00:00
this . $root . $emit ( 'hide::modal' , 'guild-form' ) ;
2017-06-02 20:55:02 +00:00
} ,
2017-08-23 03:58:13 +00:00
resetWorkingGroup ( ) {
this . workingGroup = {
name : '' ,
type : 'guild' ,
privacy : 'private' ,
description : '' ,
categories : [ ] ,
onlyLeaderCreatesChallenges : true ,
guildLeaderCantBeMessaged : true ,
privateGuild : true ,
2017-08-26 16:53:10 +00:00
allowGuildInvitationsFromNonMembers : true ,
2017-08-23 03:58:13 +00:00
} ;
} ,
2017-06-02 20:55:02 +00:00
} ,
} ;
< / script >