Allowed non-patreons to view, but not edit, sheets and libraries
This commit is contained in:
@@ -4,6 +4,7 @@ import deathSaveSchema from '/imports/api/properties/subSchemas/DeathSavesSchema
|
||||
import ColorSchema from '/imports/api/properties/subSchemas/ColorSchema.js';
|
||||
import SharingSchema from '/imports/api/sharing/SharingSchema.js';
|
||||
import {assertEditPermission} from '/imports/api/sharing/sharingPermissions.js';
|
||||
import { getUserTier } from '/imports/api/users/patreon/tiers.js';
|
||||
|
||||
import '/imports/api/creature/removeCreature.js';
|
||||
|
||||
@@ -108,6 +109,11 @@ const insertCreature = new ValidatedMethod({
|
||||
throw new Meteor.Error('Creatures.methods.insert.denied',
|
||||
'You need to be logged in to insert a creature');
|
||||
}
|
||||
let tier = getUserTier(this.userId);
|
||||
if (!tier.paidBenefits){
|
||||
throw new Meteor.Error('Creatures.methods.insert.denied',
|
||||
`The ${tier.name} tier does not allow you to insert a creature`);
|
||||
}
|
||||
|
||||
// Create the creature document
|
||||
let charId = Creatures.insert({
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { ValidatedMethod } from 'meteor/mdg:validated-method';
|
||||
import SimpleSchema from 'simpl-schema';
|
||||
import SharingSchema from '/imports/api/sharing/SharingSchema.js';
|
||||
import simpleSchemaMixin from '/imports/api/creature/mixins/simpleSchemaMixin.js';
|
||||
import { assertEditPermission, assertOwnership } from '/imports/api/sharing/sharingPermissions.js';
|
||||
import LibraryNodes from '/imports/api/library/LibraryNodes.js';
|
||||
import { getUserTier } from '/imports/api/users/patreon/tiers.js'
|
||||
|
||||
/**
|
||||
* Libraries are trees of library nodes where each node represents a character
|
||||
@@ -38,6 +40,15 @@ const insertLibrary = new ValidatedMethod({
|
||||
],
|
||||
schema: LibrarySchema.omit('owner', 'isDefault'),
|
||||
run(library) {
|
||||
if (!this.userId) {
|
||||
throw new Meteor.Error('Libraries.methods.insert.denied',
|
||||
'You need to be logged in to insert a library');
|
||||
}
|
||||
let tier = getUserTier(this.userId);
|
||||
if (!tier.paidBenefits){
|
||||
throw new Meteor.Error('Libraries.methods.insert.denied',
|
||||
`The ${tier.name} tier does not allow you to insert a library`);
|
||||
}
|
||||
library.owner = this.userId;
|
||||
return Libraries.insert(library);
|
||||
},
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import { _ } from 'meteor/underscore';
|
||||
import fetchDocByRef from '/imports/api/parenting/fetchDocByRef.js';
|
||||
import { getUserTier } from '/imports/api/users/patreon/tiers.js';
|
||||
|
||||
function assertIdValid(userId){
|
||||
if (!userId || typeof userId !== 'string'){
|
||||
throw new Meteor.Error("Permission denied",
|
||||
"No user ID given for edit permission check");
|
||||
throw new Meteor.Error('Permission denied',
|
||||
'No user ID given for edit permission check');
|
||||
}
|
||||
}
|
||||
|
||||
function assertdocExists(doc){
|
||||
if (!doc){
|
||||
throw new Meteor.Error("Permission denied",
|
||||
`No such document exists`);
|
||||
throw new Meteor.Error('Permission denied',
|
||||
'No such document exists');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +22,8 @@ export function assertOwnership(doc, userId){
|
||||
if (doc.owner === userId ){
|
||||
return true;
|
||||
} else {
|
||||
throw new Meteor.Error("Permission denied",
|
||||
`You are not the owner of this document`);
|
||||
throw new Meteor.Error('Permission denied',
|
||||
'You are not the owner of this document');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,11 +36,34 @@ export function assertOwnership(doc, userId){
|
||||
export function assertEditPermission(doc, userId) {
|
||||
assertIdValid(userId);
|
||||
assertdocExists(doc);
|
||||
if (doc.owner === userId || _.contains(doc.writers, userId)){
|
||||
let user = Meteor.users.findOne(userId, {
|
||||
fields: {
|
||||
'services.patreon': 1,
|
||||
'roles': 1,
|
||||
}
|
||||
});
|
||||
|
||||
// Admin override
|
||||
if (user.roles && user.roles.includes('admin')){
|
||||
return true;
|
||||
}
|
||||
|
||||
// Ensure the user is of a tier with paid benefits
|
||||
let tier = getUserTier(user);
|
||||
if (!tier.paidBenefits){
|
||||
throw new Meteor.Error('Edit permission denied',
|
||||
`The ${tier.name} tier does not allow you to edit this document`);
|
||||
}
|
||||
|
||||
// Ensure the user is authorized for this specific document
|
||||
if (
|
||||
doc.owner === userId ||
|
||||
_.contains(doc.writers, userId)
|
||||
){
|
||||
return true;
|
||||
} else {
|
||||
throw new Meteor.Error("Edit permission denied",
|
||||
`You do not have permission to edit this document`);
|
||||
throw new Meteor.Error('Edit permission denied',
|
||||
'You do not have permission to edit this document');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,8 +98,8 @@ export function assertViewPermission(doc, userId) {
|
||||
){
|
||||
return true;
|
||||
} else {
|
||||
throw new Meteor.Error("View permission denied",
|
||||
`You do not have permission to view this character`);
|
||||
throw new Meteor.Error('View permission denied',
|
||||
'You do not have permission to view this character');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,11 @@ export function getTierByEntitledCents(entitledCents = 0){
|
||||
export function getUserTier(user){
|
||||
if (!user) throw 'user must be provided';
|
||||
if (typeof user === 'string'){
|
||||
user = Meteor.users.findOne(user);
|
||||
user = Meteor.users.findOne(user, {
|
||||
fields: {
|
||||
'services.patreon': 1,
|
||||
}
|
||||
});
|
||||
if (!user) throw 'User not found';
|
||||
}
|
||||
const entitledCents = getEntitledCents(user);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<template lang="html">
|
||||
<v-toolbar-items v-if="creature">
|
||||
<v-btn
|
||||
v-if="editPermission"
|
||||
flat
|
||||
icon
|
||||
@click="recompute(creature._id)"
|
||||
|
||||
@@ -9,8 +9,10 @@ import LibraryEditDialog from '/imports/ui/library/LibraryEditDialog.vue';
|
||||
import LibraryNodeCreationDialog from '/imports/ui/library/LibraryNodeCreationDialog.vue';
|
||||
import LibraryNodeEditDialog from '/imports/ui/library/LibraryNodeEditDialog.vue';
|
||||
import ShareDialog from '/imports/ui/sharing/ShareDialog.vue';
|
||||
import TierTooLowDialog from '/imports/ui/user/TierTooLowDialog.vue';
|
||||
import UsernameDialog from '/imports/ui/user/UsernameDialog.vue';
|
||||
|
||||
|
||||
export default {
|
||||
CreatureFormDialog,
|
||||
CreaturePropertyCreationDialog,
|
||||
@@ -23,5 +25,6 @@ export default {
|
||||
LibraryNodeCreationDialog,
|
||||
LibraryNodeEditDialog,
|
||||
ShareDialog,
|
||||
TierTooLowDialog,
|
||||
UsernameDialog,
|
||||
};
|
||||
|
||||
@@ -1,64 +1,72 @@
|
||||
<template lang="html">
|
||||
<div
|
||||
style="
|
||||
background-color: inherit;
|
||||
overflow-y: auto;
|
||||
"
|
||||
>
|
||||
<v-expansion-panel
|
||||
style="box-shadow: none;"
|
||||
v-model="expandedLibrary"
|
||||
>
|
||||
<v-expansion-panel-content
|
||||
lazy
|
||||
v-for="library in libraries"
|
||||
:key="library._id"
|
||||
:data-id="library._id"
|
||||
>
|
||||
<template v-slot:header>
|
||||
<div class="title">{{library.name}}</div>
|
||||
</template>
|
||||
<v-card flat>
|
||||
<library-contents-container
|
||||
:library-id="library._id"
|
||||
:organize-mode="organizeMode"
|
||||
:edit-mode="editMode"
|
||||
@selected="e => $emit('selected', e)"
|
||||
:selected-node-id="selectedNodeId"
|
||||
/>
|
||||
<v-card-actions>
|
||||
<v-btn
|
||||
flat small
|
||||
style="background-color: inherit; margin-top: 0;"
|
||||
@click="insertLibraryNode(library._id)"
|
||||
:data-id="`insert-node-${library._id}`"
|
||||
>
|
||||
<v-icon>add</v-icon>
|
||||
New property
|
||||
</v-btn>
|
||||
<v-spacer/>
|
||||
<v-btn flat small icon
|
||||
@click="editLibrary(library._id)"
|
||||
>
|
||||
<v-icon>create</v-icon>
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
<v-btn
|
||||
v-show="expandedLibrary === null"
|
||||
v-if="editMode"
|
||||
flat
|
||||
color="primary"
|
||||
style="background-color: inherit;"
|
||||
@click="insertLibrary"
|
||||
data-id="insert-library-button"
|
||||
>
|
||||
<v-icon>add</v-icon>
|
||||
New library
|
||||
</v-btn>
|
||||
</div>
|
||||
<div
|
||||
style="
|
||||
background-color: inherit;
|
||||
overflow-y: auto;
|
||||
"
|
||||
>
|
||||
<v-expansion-panel
|
||||
v-model="expandedLibrary"
|
||||
style="box-shadow: none;"
|
||||
>
|
||||
<v-expansion-panel-content
|
||||
v-for="library in libraries"
|
||||
:key="library._id"
|
||||
lazy
|
||||
:data-id="library._id"
|
||||
>
|
||||
<template #header>
|
||||
<div class="title">
|
||||
{{ library.name }}
|
||||
</div>
|
||||
</template>
|
||||
<v-card flat>
|
||||
<library-contents-container
|
||||
:library-id="library._id"
|
||||
:organize-mode="organizeMode"
|
||||
:edit-mode="editMode"
|
||||
:selected-node-id="selectedNodeId"
|
||||
@selected="e => $emit('selected', e)"
|
||||
/>
|
||||
<v-card-actions>
|
||||
<v-btn
|
||||
flat
|
||||
small
|
||||
style="background-color: inherit; margin-top: 0;"
|
||||
:disabled="!editPermission(library)"
|
||||
:data-id="`insert-node-${library._id}`"
|
||||
@click="insertLibraryNode(library._id)"
|
||||
>
|
||||
<v-icon>add</v-icon>
|
||||
New property
|
||||
</v-btn>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
flat
|
||||
small
|
||||
icon
|
||||
:disabled="!editPermission(library)"
|
||||
@click="editLibrary(library._id)"
|
||||
>
|
||||
<v-icon>create</v-icon>
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
<v-btn
|
||||
v-show="expandedLibrary === null"
|
||||
v-if="editMode"
|
||||
flat
|
||||
color="primary"
|
||||
style="background-color: inherit;"
|
||||
data-id="insert-library-button"
|
||||
@click="insertLibrary"
|
||||
>
|
||||
<v-icon>add</v-icon>
|
||||
New library
|
||||
</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -66,63 +74,91 @@ import LibraryContentsContainer from '/imports/ui/library/LibraryContentsContain
|
||||
import { setDocToLastOrder } from '/imports/api/parenting/order.js';
|
||||
import LibraryNodes, { insertNode } from '/imports/api/library/LibraryNodes.js';
|
||||
import Libraries, { insertLibrary } from '/imports/api/library/Libraries.js';
|
||||
import { getUserTier } from '/imports/api/users/patreon/tiers.js';
|
||||
import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
LibraryContentsContainer,
|
||||
},
|
||||
props: {
|
||||
organizeMode: Boolean,
|
||||
editMode: Boolean,
|
||||
selectedNodeId: String,
|
||||
},
|
||||
data(){ return {
|
||||
expandedLibrary: null,
|
||||
};},
|
||||
meteor: {
|
||||
$subscribe: {
|
||||
'libraries': [],
|
||||
},
|
||||
libraries(){
|
||||
return Libraries.find({}, {
|
||||
sort: {name: 1}
|
||||
}).fetch();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
insertLibrary(){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'library-creation-dialog',
|
||||
elementId: 'insert-library-button',
|
||||
callback(library){
|
||||
if (!library) return;
|
||||
let libraryId = insertLibrary.call(library);
|
||||
return libraryId;
|
||||
}
|
||||
});
|
||||
},
|
||||
editLibrary(_id){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'library-edit-dialog',
|
||||
elementId: _id,
|
||||
data: {_id},
|
||||
});
|
||||
},
|
||||
insertLibraryNode(libraryId){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'library-node-creation-dialog',
|
||||
elementId: `insert-node-${libraryId}`,
|
||||
callback(libraryNode){
|
||||
if (!libraryNode) return;
|
||||
libraryNode.parent = {collection: "libraries", id: libraryId};
|
||||
libraryNode.ancestors = [ {collection: "libraries", id: libraryId}];
|
||||
setDocToLastOrder({collection: LibraryNodes, doc: libraryNode});
|
||||
let libraryNodeId = insertNode.call(libraryNode);
|
||||
return `tree-node-${libraryNodeId}`;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
components: {
|
||||
LibraryContentsContainer,
|
||||
},
|
||||
props: {
|
||||
organizeMode: Boolean,
|
||||
editMode: Boolean,
|
||||
selectedNodeId: String,
|
||||
},
|
||||
data(){ return {
|
||||
expandedLibrary: null,
|
||||
};},
|
||||
meteor: {
|
||||
$subscribe: {
|
||||
'libraries': [],
|
||||
},
|
||||
libraries(){
|
||||
return Libraries.find({}, {
|
||||
sort: {name: 1}
|
||||
}).fetch();
|
||||
},
|
||||
paidBenefits(){
|
||||
let tier = getUserTier(Meteor.userId());
|
||||
return tier && tier.paidBenefits;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
insertLibrary(){
|
||||
if (this.paidBenefits){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'library-creation-dialog',
|
||||
elementId: 'insert-library-button',
|
||||
callback(library){
|
||||
if (!library) return;
|
||||
let libraryId = insertLibrary.call(library);
|
||||
return libraryId;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'tier-too-low-dialog',
|
||||
elementId: 'insert-library-button',
|
||||
});
|
||||
}
|
||||
},
|
||||
editPermission(library){
|
||||
try {
|
||||
assertEditPermission(library, Meteor.userId());
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
editLibrary(_id){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'library-edit-dialog',
|
||||
elementId: _id,
|
||||
data: {_id},
|
||||
});
|
||||
},
|
||||
insertLibraryNode(libraryId){
|
||||
if (this.paidBenefits){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'library-node-creation-dialog',
|
||||
elementId: `insert-node-${libraryId}`,
|
||||
callback(libraryNode){
|
||||
if (!libraryNode) return;
|
||||
libraryNode.parent = {collection: 'libraries', id: libraryId};
|
||||
libraryNode.ancestors = [ {collection: 'libraries', id: libraryId}];
|
||||
setDocToLastOrder({collection: LibraryNodes, doc: libraryNode});
|
||||
let libraryNodeId = insertNode.call(libraryNode);
|
||||
return `tree-node-${libraryNodeId}`;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'tier-too-low-dialog',
|
||||
elementId: `insert-node-${libraryId}`,
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -53,6 +53,18 @@
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
</v-card>
|
||||
<v-btn
|
||||
color="accent"
|
||||
fab
|
||||
fixed
|
||||
bottom
|
||||
right
|
||||
data-id="new-character-button"
|
||||
@click="insertCharacter"
|
||||
>
|
||||
<v-icon>add</v-icon>
|
||||
</v-btn>
|
||||
<!--
|
||||
<v-speed-dial
|
||||
v-model="fab"
|
||||
fixed
|
||||
@@ -72,6 +84,7 @@
|
||||
<labeled-fab
|
||||
icon="face"
|
||||
label="New Character"
|
||||
data-id="new-character-button"
|
||||
@click="insertCharacter"
|
||||
/>
|
||||
<labeled-fab
|
||||
@@ -79,6 +92,7 @@
|
||||
label="New Party"
|
||||
/>
|
||||
</v-speed-dial>
|
||||
-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -86,6 +100,7 @@
|
||||
import Creatures, {insertCreature} from '/imports/api/creature/Creatures.js';
|
||||
import Parties from '/imports/api/campaign/Parties.js';
|
||||
import LabeledFab from '/imports/ui/components/LabeledFab.vue';
|
||||
import { getUserTier } from '/imports/api/users/patreon/tiers.js';
|
||||
|
||||
const characterTransform = function(char){
|
||||
char.url = `/character/${char._id}/${char.urlName || '-'}`;
|
||||
@@ -136,26 +151,21 @@
|
||||
},
|
||||
methods: {
|
||||
insertCharacter(){
|
||||
insertCreature.call((error, result) => {
|
||||
if (error){
|
||||
console.error(error);
|
||||
} else {
|
||||
this.$router.push({ path: `/character/${result}`})
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
store.commit("pushDialogStack", {
|
||||
component: CharacterCreationDialog,
|
||||
data: {},
|
||||
element: undefined,
|
||||
returnElement: undefined,
|
||||
callback(result){
|
||||
if (!result) return;
|
||||
insertCreature.call(result);
|
||||
},
|
||||
});
|
||||
*/
|
||||
let tier = getUserTier(Meteor.userId());
|
||||
if (tier.paidBenefits){
|
||||
insertCreature.call((error, result) => {
|
||||
if (error){
|
||||
console.error(error);
|
||||
} else {
|
||||
this.$router.push({ path: `/character/${result}`})
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'tier-too-low-dialog',
|
||||
elementId: 'new-character-button',
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
@@ -12,6 +12,12 @@
|
||||
You need to be at least Adventurer tier (or be invited by a Patron of
|
||||
a higher tier) to access this beta
|
||||
</h3>
|
||||
<v-btn
|
||||
href="https://www.patreon.com/join/dicecloud/checkout?rid=3002853"
|
||||
color="accent"
|
||||
>
|
||||
Join now
|
||||
</v-btn>
|
||||
</v-layout>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<template #activator="{ on }">
|
||||
<v-btn
|
||||
:loading="addResourceLoading"
|
||||
:disabled="addResourceLoading"
|
||||
:disabled="addResourceLoading || context.editPermission === false"
|
||||
icon
|
||||
large
|
||||
outline
|
||||
@@ -62,6 +62,9 @@
|
||||
AttributesConsumedListForm,
|
||||
ItemsConsumedListForm,
|
||||
},
|
||||
inject: {
|
||||
context: { default: {} }
|
||||
},
|
||||
mixins: [propertyFormMixin],
|
||||
props: {
|
||||
parentTarget: {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { RouterFactory, nativeScrollBehavior } from 'meteor/akryum:vue-router2';
|
||||
import { getUserTier } from '/imports/api/users/patreon/tiers.js';
|
||||
import LAUNCH_DATE from '/imports/constants/LAUNCH_DATE.js';
|
||||
import { acceptInviteToken } from '/imports/api/users/Invites.js';
|
||||
|
||||
@@ -48,25 +47,6 @@ function ensureLoggedIn(to, from, next){
|
||||
});
|
||||
}
|
||||
|
||||
function ensurePaidFeatures(to, from, next){
|
||||
Tracker.autorun((computation) => {
|
||||
if (userSubscription.ready()){
|
||||
computation.stop();
|
||||
const user = Meteor.user();
|
||||
if (!user){
|
||||
next({ name: 'signIn', query: { redirect: to.path} });
|
||||
return;
|
||||
}
|
||||
let tier = getUserTier(user);
|
||||
if (tier && tier.paidBenefits){
|
||||
next();
|
||||
} else {
|
||||
next('/patreon-level-too-low');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function claimInvite(to, from, next){
|
||||
Tracker.autorun((computation) => {
|
||||
if (userSubscription.ready()){
|
||||
@@ -118,7 +98,7 @@ RouterFactory.configure(factory => {
|
||||
meta: {
|
||||
title: 'Character List',
|
||||
},
|
||||
beforeEnter: ensurePaidFeatures,
|
||||
beforeEnter: ensureLoggedIn,
|
||||
},{
|
||||
path: '/library',
|
||||
components: {
|
||||
@@ -127,7 +107,7 @@ RouterFactory.configure(factory => {
|
||||
meta: {
|
||||
title: 'Library',
|
||||
},
|
||||
beforeEnter: ensurePaidFeatures,
|
||||
beforeEnter: ensureLoggedIn,
|
||||
},{
|
||||
name: 'singleLibrary',
|
||||
path: '/library/:id',
|
||||
@@ -138,7 +118,6 @@ RouterFactory.configure(factory => {
|
||||
meta: {
|
||||
title: 'Library',
|
||||
},
|
||||
beforeEnter: ensurePaidFeatures,
|
||||
},{
|
||||
path: '/character/:id/:urlName',
|
||||
components: {
|
||||
@@ -149,7 +128,6 @@ RouterFactory.configure(factory => {
|
||||
meta: {
|
||||
title: 'Character Sheet',
|
||||
},
|
||||
beforeEnter: ensurePaidFeatures,
|
||||
},{
|
||||
path: '/character/:id',
|
||||
components: {
|
||||
@@ -160,7 +138,6 @@ RouterFactory.configure(factory => {
|
||||
meta: {
|
||||
title: 'Character Sheet',
|
||||
},
|
||||
beforeEnter: ensurePaidFeatures,
|
||||
},{
|
||||
path: '/friends',
|
||||
components: {
|
||||
|
||||
49
app/imports/ui/user/TierTooLowDialog.vue
Normal file
49
app/imports/ui/user/TierTooLowDialog.vue
Normal file
@@ -0,0 +1,49 @@
|
||||
<template lang="html">
|
||||
<dialog-base>
|
||||
<v-layout
|
||||
column
|
||||
align-center
|
||||
justify-center
|
||||
>
|
||||
<h2 style="margin: 48px 28px 16px">
|
||||
Your current Patreon tier is {{ tier.name }}
|
||||
</h2>
|
||||
<h3>
|
||||
You need to be at least Adventurer tier (or be invited by a Patron of
|
||||
a higher tier) to perform this action
|
||||
</h3>
|
||||
<v-btn
|
||||
href="https://www.patreon.com/join/dicecloud/checkout?rid=3002853"
|
||||
color="accent"
|
||||
>
|
||||
Join now
|
||||
</v-btn>
|
||||
</v-layout>
|
||||
<v-spacer slot="actions" />
|
||||
<v-btn
|
||||
slot="actions"
|
||||
flat
|
||||
@click="$store.dispatch('popDialogStack')"
|
||||
>
|
||||
Cancel
|
||||
</v-btn>
|
||||
</dialog-base>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TIERS, { getUserTier } from '/imports/api/users/patreon/tiers.js';
|
||||
import DialogBase from '/imports/ui/dialogStack/DialogBase.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
DialogBase,
|
||||
},
|
||||
meteor: {
|
||||
tier(){
|
||||
let user = Meteor.user();
|
||||
if (!user) return TIERS[0];
|
||||
return getUserTier(user);
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user