147 lines
4.4 KiB
Vue
147 lines
4.4 KiB
Vue
<script setup lang="ts">
|
|
|
|
import {computed, ref} from "vue";
|
|
import {storeToRefs} from "pinia";
|
|
import {isCombined, Ledger, LedgerType, LedgerTypes, useLedgersStore} from "./ledger";
|
|
import {Modal} from "@/components";
|
|
import LedgerLabel from "./LedgerLabel.vue";
|
|
import {PlusIcon, TrashIcon} from '@heroicons/vue/24/outline';
|
|
import LedgerSelect from "@/ledger/LedgerSelect.vue";
|
|
|
|
interface Props {
|
|
ledgerId?: string;
|
|
}
|
|
|
|
const props = defineProps<Props>();
|
|
|
|
const ledgersStore = useLedgersStore();
|
|
const {ledgers} = storeToRefs(ledgersStore);
|
|
const {findById, findAllById, createMain, createCombined, updateMain, updateCombined} = ledgersStore;
|
|
|
|
const modalOpen = ref<boolean>(false);
|
|
|
|
const type = ref<LedgerType>(LedgerTypes.Main);
|
|
const name = ref("");
|
|
const members = ref<Ledger[]>([]);
|
|
const selectedLedger = ref<Ledger>();
|
|
const availableLedgers = computed(() => ledgers.value
|
|
.filter((ledger) => selectedLedger.value === ledger)
|
|
.filter(l => !members.value.includes(l)));
|
|
|
|
|
|
const addMember = () => {
|
|
if (selectedLedger.value && !members.value.includes(selectedLedger.value)) {
|
|
members.value = [...members.value, selectedLedger.value];
|
|
selectedLedger.value = undefined;
|
|
}
|
|
}
|
|
|
|
const open = () => {
|
|
const ledger = isCreating.value ? undefined : findById(props.ledgerId);
|
|
|
|
if (ledger) {
|
|
type.value = ledger.type;
|
|
name.value = ledger.name;
|
|
members.value = isCombined(ledger) ? findAllById(ledger.memberLedgerIds) : [];
|
|
} else {
|
|
type.value = LedgerTypes.Main;
|
|
name.value = "";
|
|
members.value = [];
|
|
}
|
|
modalOpen.value = true;
|
|
}
|
|
|
|
const canSave = computed(() => name.value.trim().length > 0);
|
|
const isCreating = computed(() => props.ledgerId === undefined || props.ledgerId.length === 0);
|
|
const title = computed(() => {
|
|
if (isCreating.value) {
|
|
return `Creating ${type.value === LedgerTypes.Main ? 'Main' : 'Combined'} Ledger`
|
|
}
|
|
return `Updating ${name.value}`
|
|
})
|
|
|
|
const create = () => {
|
|
if (type.value === LedgerTypes.Main) {
|
|
createMain({name: name.value})
|
|
} else {
|
|
createCombined({name: name.value, memberLedgerIds: members.value.map(l => l.ledgerId)})
|
|
}
|
|
}
|
|
|
|
const update = () => {
|
|
if (type.value === LedgerTypes.Main) {
|
|
updateMain(props.ledgerId, {name: name.value})
|
|
} else {
|
|
updateCombined(props.ledgerId, {name: name.value, memberLedgerIds: members.value.map(l => l.ledgerId)})
|
|
}
|
|
}
|
|
|
|
const save = () => {
|
|
if (!canSave.value) {
|
|
return;
|
|
}
|
|
|
|
if (isCreating.value) {
|
|
create();
|
|
} else {
|
|
update();
|
|
}
|
|
modalOpen.value = false;
|
|
}
|
|
|
|
defineExpose({ open });
|
|
</script>
|
|
|
|
<template>
|
|
<Modal v-model:open="modalOpen">
|
|
<div class="bg-slate-800 rounded pb-4 w-96">
|
|
<span class="m-2">{{ title }}</span>
|
|
<hr />
|
|
<div class="mt-4">
|
|
<div class="flex justify-center">
|
|
<div class="flex bg-slate-600 rounded-s-md p-1">
|
|
<button class="switch" :class="{active: type === LedgerTypes.Main}" @click="type = LedgerTypes.Main">Main</button>
|
|
</div>
|
|
<div class="switch flex bg-slate-600 rounded-e-md p-1">
|
|
<button class="switch" :class="{active: type === LedgerTypes.Combined}" @click="type = LedgerTypes.Combined">Combined</button>
|
|
</div>
|
|
</div>
|
|
<div class="m-4">
|
|
Name:
|
|
<div class="flex">
|
|
<input type="text" class="flex grow" v-model="name" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div v-if="type === LedgerTypes.Combined" class="ms-4 mb-4">
|
|
Member Ledgers:
|
|
<div v-for="ledger in members" :key="ledger.ledgerId" class="flex">
|
|
<LedgerLabel class="flex grow mb-2" :ledger="ledger" />
|
|
<div class="flex justify-end me-4 ms-2">
|
|
<button class="btn-icon" @click="members = members.filter(m => m !== ledger)"><TrashIcon /></button>
|
|
</div>
|
|
</div>
|
|
<div v-if="availableLedgers.length" class="flex">
|
|
<LedgerSelect v-model="selectedLedger" class="grow" :ledgers="availableLedgers" />
|
|
<div class="flex justify-end me-4 ms-2">
|
|
<button class="btn-icon" @click="addMember"><PlusIcon /></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="flex justify-end">
|
|
<button class="me-4" @click="save" :disabled="!canSave">Save</button>
|
|
</div>
|
|
</div>
|
|
</Modal>
|
|
</template>
|
|
|
|
<style scoped>
|
|
@reference "tailwindcss";
|
|
|
|
button.switch {
|
|
@apply flex items-center px-4 rounded-md bg-slate-600;
|
|
&.active {
|
|
@apply bg-emerald-500;
|
|
}
|
|
}
|
|
</style> |