Added Modals for Adding, Editing, Showing

This commit is contained in:
2025-03-14 17:49:54 +01:00
parent 14e4e79c43
commit d907f1ca01
6 changed files with 368 additions and 37 deletions

View File

@@ -7,12 +7,20 @@ const props = defineProps({
required: true,
type: String
},
createQuery: {
type: Object
},
item: {
required: true,
type: Object
},
inModal: {
type: Boolean,
}
})
const emit = defineEmits(["returnData"])
const {type} = props
@@ -38,6 +46,7 @@ const route = useRoute()
const dataStore = useDataStore()
const profileStore = useProfileStore()
const supabase = useSupabaseClient()
const modal = useModal()
const dataType = dataStore.dataTypes[type]
const openTab = ref(0)
@@ -73,17 +82,20 @@ const setupCreate = () => {
setupCreate()
const setupQuery = () => {
if(route.query) {
Object.keys(route.query).forEach(key => {
if(props.mode === "create" && (route.query || props.createQuery)) {
let data = !props.inModal ? route.query : props.createQuery
Object.keys(data).forEach(key => {
if(dataType.templateColumns.find(i => i.key === key)) {
if (["customer", "contract", "plant", "contact", "project"].includes(key)) {
item.value[key] = Number(route.query[key])
item.value[key] = Number(data[key])
} else {
item.value[key] = route.query[key]
item.value[key] = data[key]
}
} else if(key === "resources") {
/*item.value[key] = route.query[key]*/
JSON.parse(route.query[key]).forEach(async (i) => {
/*item.value[key] = data[key]*/
JSON.parse(data[key]).forEach(async (i) => {
console.log(i)
let type = i.substring(0,1)
let id = i.substring(2,i.length)
@@ -180,10 +192,37 @@ const calcSaveAllowed = (item) => {
watch(item.value, async (newItem, oldItem) => {
calcSaveAllowed(newItem)
})
const createItem = async () => {
let ret = null
if(props.inModal) {
ret = await dataStore.createNewItem(type,item.value,true)
} else {
ret = dataStore.createNewItem(type,item.value)
}
emit('returnData', ret)
}
const updateItem = async () => {
let ret = null
if(props.inModal) {
ret = await dataStore.updateItem(type,item.value, oldItem.value,true)
} else {
ret = await dataStore.updateItem(type,item.value, oldItem.value)
}
emit('returnData', ret)
}
</script>
<template>
<UDashboardNavbar
v-if="!props.inModal"
:ui="{center: 'flex items-stretch gap-1.5 min-w-0'}"
>
<template #left>
@@ -217,14 +256,14 @@ watch(item.value, async (newItem, oldItem) => {
</ButtonWithConfirm>
<UButton
v-if="item.id"
@click="dataStore.updateItem(type,item, oldItem)"
@click="updateItem"
:disabled="!saveAllowed"
>
Speichern
</UButton>
<UButton
v-else
@click="dataStore.createNewItem(type,item)"
@click="createItem"
:disabled="!saveAllowed"
>
Erstellen
@@ -238,6 +277,40 @@ watch(item.value, async (newItem, oldItem) => {
</UButton>
</template>
</UDashboardNavbar>
<UDashboardNavbar
v-else
:ui="{center: 'flex items-stretch gap-1.5 min-w-0'}"
>
<template #center>
<h1
v-if="item"
:class="['text-xl','font-medium']"
>{{item.id ? `${dataType.labelSingle} bearbeiten` : `${dataType.labelSingle} erstellen` }}</h1>
</template>
<template #right>
<UButton
v-if="item.id"
@click="updateItem"
:disabled="!saveAllowed"
>
Speichern
</UButton>
<UButton
v-else
@click="createItem"
:disabled="!saveAllowed"
>
Erstellen
</UButton>
<UButton
@click="modal.close()"
color="red"
class="ml-2"
icon="i-heroicons-x-mark"
variant="outline"
/>
</template>
</UDashboardNavbar>
<UDashboardPanelContent>
<UForm
class="p-5"

View File

@@ -0,0 +1,82 @@
<script setup>
import StandardEntityModal from "~/components/StandardEntityModal.vue";
const props = defineProps({
type: {
type: String,
required: true
},
id: {
type: String,
},
createQuery: {
type: Object,
},
buttonShow: {
type: Boolean,
default: true
},
buttonEdit: {
type: Boolean,
default: true
},
buttonCreate: {
type: Boolean,
default: true
}
})
const emit = defineEmits(["returnData"])
const modal = useModal()
</script>
<template>
<UButton
variant="outline"
class="w-25 ml-2"
v-if="props.id && props.buttonShow"
icon="i-heroicons-eye"
@click="modal.open(StandardEntityModal, {
id: props.id,
type: props.type,
mode: 'show',
})"
/>
<UButton
variant="outline"
class="w-25 ml-2"
v-if="props.id && props.buttonEdit"
icon="i-heroicons-pencil-solid"
@click="modal.open(StandardEntityModal, {
id: props.id,
type: props.type,
mode: 'edit',
onReturnData(data) {
emit('returnData', data)
}
})"
/>
<UButton
variant="outline"
class="w-25 ml-2"
v-if="!props.id && props.buttonCreate"
icon="i-heroicons-plus"
@click="modal.open(StandardEntityModal, {
type: props.type,
mode: 'create',
createQuery: props.createQuery,
onReturnData(data) {
emit('returnData', data)
}
})"
/>
</template>
<style scoped>
</style>

View File

@@ -9,6 +9,9 @@ const props = defineProps({
item: {
required: true,
type: Object
},
inModal: {
type: Boolean,
}
})
@@ -37,6 +40,7 @@ const dataStore = useDataStore()
const profileStore = useProfileStore()
const supabase = useSupabaseClient()
const files = useFiles()
const modal = useModal()
const dataType = dataStore.dataTypes[type]
@@ -168,6 +172,7 @@ const getAvailableQueryStringData = (keys) => {
<template>
<UDashboardNavbar
v-if="!props.inModal"
:ui="{center: 'flex items-stretch gap-1.5 min-w-0'}"
>
<template #left>
@@ -200,6 +205,26 @@ const getAvailableQueryStringData = (keys) => {
</UButton>
</template>
</UDashboardNavbar>
<UDashboardNavbar
v-else
:ui="{center: 'flex items-stretch gap-1.5 min-w-0'}"
>
<template #center>
<h1
v-if="item"
:class="['text-xl','font-medium']"
>{{item ? `${dataType.labelSingle}${props.item[dataType.templateColumns.find(i => i.title).key] ? ': ' + props.item[dataType.templateColumns.find(i => i.title).key] : ''}`: '' }}</h1>
</template>
<template #right>
<UButton
@click="modal.close()"
color="red"
class="ml-2"
icon="i-heroicons-x-mark"
variant="outline"
/>
</template>
</UDashboardNavbar>
<UTabs
:items="dataType.showTabs"
v-if="props.item.id"

View File

@@ -0,0 +1,97 @@
<script setup>
const toast = useToast()
const dataStore = useDataStore()
const supabase = useSupabaseClient()
const modal = useModal()
const props = defineProps({
type: {
type: String,
required: true
},
mode: {
type: String,
required: true,
default: "show"
},
createQuery: {
type: Object
},
id: {
type: String,
},
})
const emit = defineEmits(["updateNeeded","returnData"])
const dataType = dataStore.dataTypes[props.type]
const loaded = ref(false)
const items = ref([])
const item = ref({})
const setupPage = async () => {
if(props.mode === "show") {
//Load Data for Show
item.value = await useSupabaseSelectSingle(props.type, props.id, dataType.supabaseSelectWithInformation || "*")
} else if(props.mode === "edit") {
//Load Data for Edit
const data = JSON.stringify((await supabase.from(props.type).select().eq("id", props.id).single()).data)
//await useSupabaseSelectSingle(type, route.params.id)
item.value = data
} else if(props.mode === "create") {
//Load Data for Create
item.value = JSON.stringify({})
} else if(props.mode === "list") {
//Load Data for List
items.value = await useSupabaseSelect(props.type, dataType.supabaseSelectWithInformation || "*", dataType.supabaseSortColumn,dataType.supabaseSortAscending || false)
}
loaded.value = true
}
setupPage()
</script>
<template>
<UModal :fullscreen="props.mode === 'show'">
<EntityShow
v-if="loaded && props.mode === 'show'"
:type="props.type"
:item="item"
@updateNeeded="setupPage"
:key="item"
:in-modal="true"
/>
<EntityEdit
v-else-if="loaded && (props.mode === 'edit' || props.mode === 'create')"
:type="props.type"
:item="item"
:inModal="true"
@return-data="(data) => emit('return-data',data)"
:createQuery="props.createQuery"
/>
<!-- <EntityList
v-else-if="loaded && props.mode === 'list'"
:type="props.type"
:items="items"
/>-->
<UProgress
v-else
animation="carousel"
class="p-5 mt-10"
/>
</UModal>
</template>
<style scoped>
</style>

View File

@@ -3,12 +3,15 @@ import dayjs from "dayjs"
import Handlebars from "handlebars"
import { v4 as uuidv4 } from 'uuid';
import {useFunctions} from "~/composables/useFunctions.js";
import StandardEntityModal from "~/components/StandardEntityModal.vue";
import EntityModalButtons from "~/components/EntityModalButtons.vue";
const dataStore = useDataStore()
const profileStore = useProfileStore()
const route = useRoute()
const router = useRouter()
const supabase = useSupabaseClient()
const modal = useModal()
definePageMeta({
@@ -321,7 +324,14 @@ const setTaxType = () => {
}
}
const setCustomerData = () => {
const setCustomerData = async (customerId) => {
if(customerId){
itemInfo.value.customer = customerId
}
customers.value = await useSupabaseSelect("customers")
let customer = customers.value.find(i => i.id === itemInfo.value.customer)
console.log(customer)
@@ -1358,31 +1368,67 @@ const setRowData = (row) => {
searchable-placeholder="Suche..."
v-model="itemInfo.customer"
@change="setCustomerData"
class="flex-auto mr-2"
class="flex-auto"
>
<UButton
:color="itemInfo.customer ? 'primary' : 'rose'"
variant="outline"
class="w-full"
>
{{itemInfo.customer ? customers.find(i => i.id === itemInfo.customer).name : "Kein Kunde ausgewählt"}}
{{customers.find(i => i.id === itemInfo.customer) ? customers.find(i => i.id === itemInfo.customer).name : "Kein Kunde ausgewählt"}}
<UIcon name="i-heroicons-chevron-right-20-solid" class="w-5 h-5 transition-transform text-gray-400 dark:text-gray-500" :class="['transform rotate-90']" />
</UButton>
</USelectMenu>
<EntityModalButtons
type="customers"
:id="itemInfo.customer"
@return-data="(data) => setCustomerData(data.id)"
/>
<!-- <UButton
variant="outline"
class="w-25 ml-2"
v-if="itemInfo.customer"
icon="i-heroicons-eye"
@click="modal.open(StandardEntityModal, {
id: itemInfo.customer,
type: 'customers',
mode: 'show',
})"
/>
<UButton
variant="outline"
class="w-25"
class="w-25 ml-2"
v-if="itemInfo.customer"
icon="i-heroicons-arrow-right-end-on-rectangle"
@click="router.push(`/standardEntity/customers/show/${itemInfo.customer}`)"
>Kunde</UButton>
icon="i-heroicons-pencil-solid"
@click="modal.open(StandardEntityModal, {
id: itemInfo.customer,
type: 'customers',
mode: 'edit',
onReturnData(data) {
setCustomerData()
}
})"
/>
<UButton
variant="outline"
class="w-25 ml-2"
v-if="!itemInfo.customer"
icon="i-heroicons-plus"
@click="modal.open(StandardEntityModal, {
type: 'customers',
mode: 'create',
onReturnData(data) {
setCustomerData(data.id)
}
})"
/>-->
</div>
<UAlert
v-if="itemInfo.customer"
v-if="customers.find(i => i.id === itemInfo.customer)"
class="mt-2"
variant="solid"
color="white"
@@ -1427,12 +1473,18 @@ const setRowData = (row) => {
{{dataStore.getContactById(itemInfo.contact) ? dataStore.getContactById(itemInfo.contact).fullName : "Kein Kontakt ausgewählt"}}
</template>
</USelectMenu>
<UButton
<!-- <UButton
variant="outline"
v-if="itemInfo.contact"
icon="i-heroicons-arrow-right-end-on-rectangle"
@click="router.push(`/standardEntity/contacts/show/${itemInfo.contact}`)"
>Kontakt</UButton>
>Kontakt</UButton>-->
<EntityModalButtons
type="contacts"
:id="itemInfo.contact"
:create-query="{customerId: itemInfo.customer}"
@return-data="(data) => itemInfo.contact = data.id"
/>
</InputGroup>
</UFormGroup>
@@ -1629,12 +1681,12 @@ const setRowData = (row) => {
icon="i-heroicons-x-mark"
@click="itemInfo.plant = null"
/>
<UButton
variant="outline"
v-if="itemInfo.plant"
icon="i-heroicons-arrow-right-end-on-rectangle"
@click="router.push(`/standardEntity/plants/show/${itemInfo.plant}`)"
>Objekt</UButton>
<EntityModalButtons
type="plants"
:id="itemInfo.plant"
:create-query="{customer: itemInfo.customer}"
@return-data="(data) => itemInfo.plant = data.id"
/>
</InputGroup>
</UFormGroup>
@@ -1668,12 +1720,12 @@ const setRowData = (row) => {
icon="i-heroicons-x-mark"
@click="itemInfo.project = null"
/>
<UButton
variant="outline"
v-if="itemInfo.project"
icon="i-heroicons-arrow-right-end-on-rectangle"
@click="router.push(`/standardEntity/projects/show/${itemInfo.project}`)"
>Projekt</UButton>
<EntityModalButtons
type="projects"
:id="itemInfo.project"
:create-query="{customer: itemInfo.customer, plant: itemInfo.plant}"
@return-data="(data) => itemInfo.project = data.id"
/>
</InputGroup>
</UFormGroup>

View File

@@ -51,6 +51,7 @@ export const useDataStore = defineStore('data', () => {
const profileStore = useProfileStore()
const toast = useToast()
const router = useRouter()
const modal = useModal()
const dataTypes = {
tasks: {
@@ -2417,7 +2418,7 @@ export const useDataStore = defineStore('data', () => {
}
}
async function createNewItem (dataType,data){
async function createNewItem (dataType,data,noRedirect=false){
if(typeof(data) === 'object') {
data = {...data, tenant: profileStore.currentTenant}
} else if(typeof(data) === 'array') {
@@ -2476,19 +2477,19 @@ export const useDataStore = defineStore('data', () => {
toast.add({title: `${dataTypes[dataType].labelSingle} hinzugefügt`})
if(dataTypes[dataType].redirect) {
if(dataTypes[dataType].redirect && !noRedirect) {
if(dataTypes[dataType].isStandardEntity) {
await router.push(dataTypes[dataType].redirectToList ? `/standardEntity/${dataType}` : `/standardEntity/${dataType}/show/${returnData.id}`)
} else {
await router.push(dataTypes[dataType].redirectToList ? `/${dataType}` : `/${dataType}/show/${returnData.id}`)
}
}
return supabaseData
modal.close()
return supabaseData[0]
}
}
async function updateItem (dataType, data, oldData = null) {
async function updateItem (dataType, data, oldData = null, noRedirect = false) {
//console.log(dataType, data)
//Temporary Fix TODO: Remove and build Solution
data = JSON.parse(JSON.stringify(data))
@@ -2536,14 +2537,15 @@ export const useDataStore = defineStore('data', () => {
//await eval(dataType + '.value[' + dataType + '.value.findIndex(i => i.id === ' + JSON.stringify(data.id) + ')] = ' + JSON.stringify(supabaseData[0]))
//if(dataType === 'profiles') await fetchProfiles()
toast.add({title: `${dataTypes[dataType].labelSingle} gespeichert`})
if(dataTypes[dataType].redirect) {
if(dataTypes[dataType].redirect && !noRedirect) {
if(dataTypes[dataType].isStandardEntity) {
await router.push(dataTypes[dataType].redirectToList ? `/standardEntity/${dataType}` : `/standardEntity/${dataType}/show/${data.id}`)
} else {
await router.push(dataTypes[dataType].redirectToList ? `/${dataType}` : `/${dataType}/show/${data.id}`)
}
}
return supabaseData
modal.close()
return supabaseData[0]
}
}