Files
DiceCloud/app/imports/client/ui/creature/archive/ArchiveDialog.vue
2022-11-19 17:51:50 +02:00

226 lines
6.2 KiB
Vue

<template lang="html">
<dialog-base>
<template #toolbar>
<v-toolbar-title>
{{ mode === 'archive' ? 'Archive' : 'Restore' }}
</v-toolbar-title>
<v-spacer />
<v-btn-toggle
v-model="mode"
mandatory
>
<v-btn value="archive">
<span>Archive</span>
<v-icon right>
mdi-archive-arrow-down
</v-icon>
</v-btn>
<v-btn value="restore">
<span>Restore</span>
<v-icon right>
mdi-archive-arrow-up-outline
</v-icon>
</v-btn>
</v-btn-toggle>
</template>
<creature-folder-list
selection
:creatures="mode === 'archive' ? CreaturesWithNoParty : archiveCreaturesWithNoParty"
:folders="mode === 'archive' ? folders : archivefolders"
:selected-creature="selectedCreature"
@creature-selected="id => selectedCreature = id"
/>
<v-spacer slot="actions" />
<v-btn
slot="actions"
text
:loading="archiveActionLoading"
:disabled="!numSelected || (mode === 'restore' && characterSlots <= 0)"
color="primary"
@click="archiveAction"
>
<template v-if="mode === 'restore' && characterSlots <= 0">
No Character Slots Left
</template>
<template v-else>
{{ mode === 'archive' ? 'Archive' : 'Restore' }}
</template>
</v-btn>
<v-btn
slot="actions"
text
@click="$store.dispatch('popDialogStack')"
>
Close
</v-btn>
</dialog-base>
</template>
<script lang="js">
import DialogBase from '/imports/client/ui/dialogStack/DialogBase.vue';
import Creatures from '/imports/api/creature/creatures/Creatures.js';
import CreatureFolders from '/imports/api/creature/creatureFolders/CreatureFolders.js';
import CreatureFolderList from '/imports/client/ui/creature/creatureList/CreatureFolderList.vue';
import ArchiveCreatureFiles from '/imports/api/creature/archive/ArchiveCreatureFiles.js';
import archiveCreatureToFile from '/imports/api/creature/archive/methods/archiveCreatureToFile.js';
import restoreCreatureFromFile from '/imports/api/creature/archive/methods/restoreCreatureFromFile.js';
import { snackbar } from '/imports/client/ui/components/snackbars/SnackbarQueue.js';
import { uniq, flatten } from 'lodash';
import { characterSlotsRemaining } from '/imports/api/creature/creatures/methods/assertHasCharacterSlots.js';
const characterTransform = function(char){
char.url = `/character/${char._id}/${char.urlName || '-'}`;
char.initial = char.name && char.name[0] || '?';
return char;
};
const fileTransform = function(file){
return {
_id: file._id,
name: file.meta.creatureName,
owner: file.userId,
creatureId: file.meta.creatureId,
};
}
const creatureFields = {
'color': 1,
'avatarPicture': 1,
'name': 1,
'initial': 1,
'alignment': 1,
'gender': 1,
'race': 1,
'readers': 1,
'writers': 1,
'owner': 1,
};
export default {
components: {
DialogBase,
CreatureFolderList,
},
data(){return {
selectedCreature: null,
mode: 'archive',
archiveActionLoading: false,
}},
computed: {
numSelected(){
return this.selectedCreature ? 1 : 0;
},
},
watch: {
mode(){
this.selectedCreature = null;
},
},
methods: {
archiveAction(){
if (!this.selectedCreature) return;
this.archiveActionLoading = true;
if (this.mode === 'archive'){
archiveCreatureToFile.call({
creatureId: this.selectedCreature,
}, error => {
this.archiveActionLoading = false;
if (!error) return;
console.error(error);
snackbar({text: error.reason});
});
} else if (this.mode === 'restore'){
restoreCreatureFromFile.call({
fileId: this.selectedCreature,
}, error => {
this.archiveActionLoading = false;
if (!error) return;
console.error(error);
snackbar({text: error.reason});
});
}
this.selectedCreature = null;
}
},
meteor: {
$subscribe: {
'archivedCreatures': [],
'archiveCreatureFiles': [],
'characterList': [],
},
characterSlots(){
return characterSlotsRemaining(Meteor.userId());
},
folders(){
const userId = Meteor.userId();
let folders = CreatureFolders.find(
{owner: userId, archived: {$ne: true}},
{sort: {order: 1}},
).map(folder => {
folder.creatures = Creatures.find(
{
_id: {$in: folder.creatures || []},
owner: userId,
}, {
sort: {name: 1},
fields: creatureFields,
}
).map(characterTransform);
return folder;
});
folders = folders.filter(folder => !!folder.creatures.length);
return folders;
},
CreaturesWithNoParty() {
var userId = Meteor.userId();
var charArrays = CreatureFolders.find({owner: userId}).map(p => p.creatures);
var folderChars = uniq(flatten(charArrays));
return Creatures.find(
{
_id: {$nin: folderChars},
owner: userId,
}, {
sort: {name: 1},
fields: creatureFields,
}
).map(characterTransform);
},
archivefolders(){
const userId = Meteor.userId();
let folders = CreatureFolders.find(
{owner: userId},
{sort: {order: 1}},
).map(folder => {
folder.creatures = ArchiveCreatureFiles.find(
{
'meta.creatureId': {$in: folder.creatures || []},
userId,
}, {
sort: {'meta.creatureName': 1},
}
).map(fileTransform);
return folder;
});
folders = folders.filter(folder => !!folder.creatures.length);
return folders;
},
archiveCreaturesWithNoParty() {
var userId = Meteor.userId();
var charArrays = CreatureFolders.find({owner: userId}).map(p => p.creatures);
var folderChars = uniq(flatten(charArrays));
return ArchiveCreatureFiles.find(
{
'meta.creatureId': {$nin: folderChars},
userId,
}, {
sort: {'meta.creatureName': 1},
}
).map(fileTransform);
},
}
}
</script>
<style lang="css" scoped>
</style>