19
src/App.vue
19
src/App.vue
@@ -3,5 +3,24 @@ import { RouterView } from 'vue-router'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<RegisterModal v-if="modal === 'register'" />
|
||||
<DeregisterModal v-if="modal === 'deregister'" />
|
||||
<RouterView />
|
||||
</template>
|
||||
<script>
|
||||
import { mapActions } from 'vuex'
|
||||
import DeregisterModal from './components/modals/DeregisterModal.vue'
|
||||
import RegisterModal from './components/modals/RegisterModal.vue'
|
||||
|
||||
export default {
|
||||
components: { DeregisterModal, RegisterModal },
|
||||
computed: {
|
||||
modal() {
|
||||
return this.$store.state.modal.modal
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['openModal', 'closeModal'])
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
80
src/components/modals/DeregisterModal.vue
Normal file
80
src/components/modals/DeregisterModal.vue
Normal file
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<div
|
||||
id="popup-modal"
|
||||
tabindex="-1"
|
||||
class="fixed top-0 left-0 right-0 z-50 flex justify-center text-center p-4 overflow-x-hidden overflow-y-auto md:inset-0 h-modal md:h-full">
|
||||
<div class="relative w-full h-full max-w-md md:h-auto">
|
||||
<div class="relative bg-white rounded-lg shadow dark:bg-gray-700">
|
||||
<button
|
||||
type="button"
|
||||
class="absolute top-3 right-2.5 text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-800 dark:hover:text-white"
|
||||
data-modal-hide="popup-modal"
|
||||
@click="closeModal()">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="w-5 h-5"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<span class="sr-only">Close modal</span>
|
||||
</button>
|
||||
<div class="p-6 text-center">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="mx-auto mb-4 text-gray-400 w-14 h-14 dark:text-gray-200"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
<h3 class="mb-5 text-lg font-normal text-gray-500 dark:text-gray-400">
|
||||
Bist du sicher, dass du abmelden möchtest?
|
||||
</h3>
|
||||
<button
|
||||
data-modal-hide="popup-modal"
|
||||
type="button"
|
||||
class="text-white bg-red-600 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 dark:focus:ring-red-800 font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center mr-2"
|
||||
@click="deregister()">
|
||||
Ja, bin sicher
|
||||
</button>
|
||||
<button
|
||||
data-modal-hide="popup-modal"
|
||||
type="button"
|
||||
class="text-gray-500 bg-white hover:bg-gray-100 focus:ring-4 focus:outline-none focus:ring-gray-200 rounded-lg border border-gray-200 text-sm font-medium px-5 py-2.5 hover:text-gray-900 focus:z-10 dark:bg-gray-700 dark:text-gray-300 dark:border-gray-500 dark:hover:text-white dark:hover:bg-gray-600 dark:focus:ring-gray-600"
|
||||
@click="closeModal()">
|
||||
Nein, stornieren
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapActions } from 'vuex'
|
||||
import { misapply } from '../../service/ContractsService';
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
selectedContract() {
|
||||
return this.$store.state.contracts.selectedContract
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['closeModal']),
|
||||
deregister() {
|
||||
misapply(this.selectedContract)
|
||||
this.closeModal()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
70
src/components/modals/RegisterModal.vue
Normal file
70
src/components/modals/RegisterModal.vue
Normal file
@@ -0,0 +1,70 @@
|
||||
<template>
|
||||
<div
|
||||
id="popup-modal"
|
||||
tabindex="-1"
|
||||
class="fixed top-0 left-0 right-0 z-50 flex justify-center text-center p-4 overflow-x-hidden overflow-y-auto md:inset-0 h-modal md:h-full">
|
||||
<div class="relative w-full h-full max-w-md md:h-auto">
|
||||
<div class="relative bg-white rounded-lg shadow dark:bg-gray-700" @click="closeModal()">
|
||||
<button
|
||||
type="button"
|
||||
class="absolute top-3 right-2.5 text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-800 dark:hover:text-white"
|
||||
data-modal-hide="popup-modal">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="w-5 h-5"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<span class="sr-only">Close modal</span>
|
||||
</button>
|
||||
<div class="p-6 text-center">
|
||||
<font-awesome-icon icon="fa-solid fa-circle-question" class="h-12" />
|
||||
<h3 class="mb-5 text-lg font-normal text-gray-500 dark:text-gray-400">
|
||||
Wie möchtest du anmelden? Als Leiter oder Mitarbeiter
|
||||
</h3>
|
||||
<button
|
||||
class="bg-blue-500 text-white active:bg-emerald-600 font-bold uppercase px-4 py-2 rounded shadow hover:shadow-md outline-none focus:outline-none mr-3 mb-1 ease-linear transition-all duration-150"
|
||||
type="button"
|
||||
@click="apply('leiter')">
|
||||
<font-awesome-icon icon="fa-solid fa-chalkboard-user" class="h-5" /><br />
|
||||
Leiter
|
||||
</button>
|
||||
<button
|
||||
class="bg-blue-500 text-white active:bg-emerald-600 font-bold uppercase px-4 py-2 rounded shadow hover:shadow-md outline-none focus:outline-none mr-1 mb-1 ease-linear transition-all duration-150"
|
||||
type="button"
|
||||
@click="apply('mitarbeiter')">
|
||||
<font-awesome-icon icon="fa-solid fa-user-large" class="h-5" /><br />
|
||||
Mitarbeiter
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapActions } from 'vuex'
|
||||
import { applyContract } from '../../service/ContractsService'
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
selectedContract() {
|
||||
return this.$store.state.contracts.selectedContract
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['closeModal']),
|
||||
apply(role) {
|
||||
const id = this.selectedContract
|
||||
if (id === null) {
|
||||
//TODO: router push error page
|
||||
}
|
||||
applyContract(id, role)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -95,7 +95,7 @@
|
||||
<td class="text align-top text-xl pl-4 max-sm:text-base py-2">Beispiele:</td>
|
||||
<td class="w-full pl-2 text-lg py-2">
|
||||
<ul class="list-disc pl-4">
|
||||
<li v-for="(example, index) in contract.examples" :key="index">
|
||||
<li v-for="(example, index) in contract.examples" :key="example">
|
||||
<a :href="example" class="underline">
|
||||
Link {{ index + 1 }}
|
||||
<font-awesome-icon
|
||||
|
||||
@@ -11,7 +11,9 @@ import {
|
||||
faEnvelope,
|
||||
faArrowUpRightFromSquare,
|
||||
faCircleUser,
|
||||
faUserLarge
|
||||
faUserLarge,
|
||||
faCircleQuestion,
|
||||
faChalkboardUser
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
import './assets/main.css'
|
||||
@@ -23,6 +25,8 @@ library.add(faEnvelope)
|
||||
library.add(faArrowUpRightFromSquare)
|
||||
library.add(faCircleUser)
|
||||
library.add(faUserLarge)
|
||||
library.add(faCircleQuestion)
|
||||
library.add(faChalkboardUser)
|
||||
|
||||
const i18n = createI18n()
|
||||
|
||||
|
||||
@@ -45,3 +45,32 @@ export async function getContractById(identifier) {
|
||||
router.push('/error?message=' + error.message + '&code=' + error.code)
|
||||
})
|
||||
}
|
||||
|
||||
export async function applyContract(contractID, prefRole) {
|
||||
return HttpClient.post('/contract/apply', {
|
||||
id: contractID,
|
||||
role: prefRole
|
||||
})
|
||||
.then(resp => {
|
||||
//TODO: send also auth token with request
|
||||
return resp.data
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error)
|
||||
router.push('/error?message=' + error.message + '&code=' + error.code)
|
||||
})
|
||||
}
|
||||
|
||||
export async function misapply(contractID) {
|
||||
return HttpClient.post('/contract/misapply', {
|
||||
id: contractID
|
||||
})
|
||||
.then(resp => {
|
||||
//TODO: send also auth token with request
|
||||
return resp.data
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error)
|
||||
router.push('/error?message=' + error.message + '&code=' + error.code)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@ export default {
|
||||
state: () => ({
|
||||
contracts: [],
|
||||
currentContract: null,
|
||||
openContracts: []
|
||||
openContracts: [],
|
||||
selectedContract: null
|
||||
}),
|
||||
mutations: {
|
||||
initContracts(state, data) {
|
||||
@@ -15,6 +16,9 @@ export default {
|
||||
},
|
||||
setCurrentContract(state, data) {
|
||||
state.currentContract = data
|
||||
},
|
||||
setSelectedContract(state, contractID) {
|
||||
state.selectedContract = contractID
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createStore } from 'vuex'
|
||||
import contracts from './contracts.module'
|
||||
import moduleB from './moduleB.module'
|
||||
import modal from './modal.module'
|
||||
import keycloak from './keycloak.module'
|
||||
import createPersistedState from 'vuex-persistedstate'
|
||||
|
||||
@@ -8,7 +8,7 @@ export default createStore({
|
||||
modules: {
|
||||
keycloak: keycloak,
|
||||
contracts: contracts,
|
||||
b: moduleB
|
||||
modal: modal
|
||||
},
|
||||
plugins: [createPersistedState()]
|
||||
})
|
||||
|
||||
22
src/store/modal.module.js
Normal file
22
src/store/modal.module.js
Normal file
@@ -0,0 +1,22 @@
|
||||
export default {
|
||||
state: () => ({
|
||||
modal: ''
|
||||
}),
|
||||
mutations: {
|
||||
setModal(state, modalName) {
|
||||
state.modal = modalName
|
||||
},
|
||||
resetModal(state) {
|
||||
state.modal = ''
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
openModal({ commit }, modalName) {
|
||||
commit('setModal', modalName)
|
||||
},
|
||||
closeModal({ commit }) {
|
||||
commit('resetModal')
|
||||
}
|
||||
},
|
||||
getters: {}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
export default {
|
||||
state: () => ({}),
|
||||
mutations: {},
|
||||
actions: {},
|
||||
getters: {}
|
||||
}
|
||||
@@ -2,71 +2,81 @@
|
||||
import Navbar from '../components/Navbar.vue'
|
||||
</script>
|
||||
<template>
|
||||
<Navbar /><!-- Causes rerendering each time TODO: possible use in App.vue-->
|
||||
<div class="flex justify-center pt-8 pb-8">
|
||||
<p
|
||||
class="text-2xl md:text-2xl lg:text-3xl xl:text-4xl 2xl:text-5xl font-serif font-medium tracking-wide flex justify-center items-center">
|
||||
<span class="inline-block w-5 h-1 mr-4 bg-gray-900 ::before"></span>
|
||||
Offene Aufträge
|
||||
<span class="inline-block w-5 h-1 ml-4 bg-gray-900 ::after"></span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex justify-center pb-6">
|
||||
<div class="overflow-x-auto">
|
||||
<table
|
||||
v-if="openContracts"
|
||||
class="min-w-full border-collapse bg-white border border-gray-600">
|
||||
<thead class="bg-gray-800 text-white">
|
||||
<tr>
|
||||
<th class="py-3 px-4 uppercase font-semibold text-sm text-center">Id</th>
|
||||
<th class="py-3 px-4 uppercase font-semibold text-sm text-center">Name</th>
|
||||
<th class="py-3 px-4 uppercase font-semibold text-sm text-center">Status</th>
|
||||
<th class="py-3 px-4 uppercase font-semibold text-sm text-center">Planed Date</th>
|
||||
<th class="w-1/3 py-3 px-4 uppercase font-semibold text-sm text-center">Notes</th>
|
||||
<th class="py-3 px-4 uppercase font-semibold text-sm text-center">Aktion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-gray-700">
|
||||
<tr
|
||||
v-for="(contract, index) in openContracts"
|
||||
:key="contract.id"
|
||||
:class="{ 'bg-gray-100': index % 2 !== 0 }">
|
||||
<td class="py-3 px-4 text-center">{{ contract.id }}</td>
|
||||
<td class="py-3 px-4 text-center">{{ contract.name }}</td>
|
||||
<td class="py-3 px-4 text-center">
|
||||
<!-- TODO: set color specific from status. for colors use https://www.creative-tim.com/learning-lab/tailwind-starter-kit/documentation/css/labels -->
|
||||
<span class="text-emerald-600 bg-emerald-200 rounded-full py-1 px-2">{{
|
||||
contract.status
|
||||
}}</span>
|
||||
</td>
|
||||
<td class="py-3 px-4 text-center">
|
||||
{{ new Date(contract.appointment).toDateString() }}
|
||||
</td>
|
||||
<td class="py-3 px-4 text-center">{{ contract.notes }}</td>
|
||||
<td class="text-left py-2">
|
||||
<RouterLink to="/contract?id=TESTID">
|
||||
<div>
|
||||
<Navbar /><!-- Causes rerendering each time TODO: possible use in App.vue-->
|
||||
<div class="flex justify-center pt-8 pb-8">
|
||||
<p
|
||||
class="text-2xl md:text-2xl lg:text-3xl xl:text-4xl 2xl:text-5xl font-serif font-medium tracking-wide flex justify-center items-center">
|
||||
<span class="inline-block w-5 h-1 mr-4 bg-gray-900 ::before"></span>
|
||||
Offene Aufträge
|
||||
<span class="inline-block w-5 h-1 ml-4 bg-gray-900 ::after"></span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex justify-center pb-6">
|
||||
<div class="overflow-x-auto">
|
||||
<table
|
||||
v-if="openContracts"
|
||||
class="min-w-full border-collapse bg-white border border-gray-600">
|
||||
<thead class="bg-gray-800 text-white">
|
||||
<tr>
|
||||
<th class="py-3 px-4 uppercase font-semibold text-sm text-center">Id</th>
|
||||
<th class="py-3 px-4 uppercase font-semibold text-sm text-center">Name</th>
|
||||
<th class="py-3 px-4 uppercase font-semibold text-sm text-center">Status</th>
|
||||
<th class="py-3 px-4 uppercase font-semibold text-sm text-center">Planed Date</th>
|
||||
<th class="w-1/3 py-3 px-4 uppercase font-semibold text-sm text-center">Notes</th>
|
||||
<th class="py-3 px-4 uppercase font-semibold text-sm text-center">Aktion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-gray-700">
|
||||
<tr
|
||||
v-for="(contract, index) in openContracts"
|
||||
:key="contract.id"
|
||||
:class="{ 'bg-gray-100': index % 2 !== 0 }">
|
||||
<td class="py-3 px-4 text-center">{{ contract.id }}</td>
|
||||
<td class="py-3 px-4 text-center">{{ contract.name }}</td>
|
||||
<td class="py-3 px-4 text-center">
|
||||
<!-- TODO: set color specific from status. for colors use https://www.creative-tim.com/learning-lab/tailwind-starter-kit/documentation/css/labels -->
|
||||
<span class="text-emerald-600 bg-emerald-200 rounded-full py-1 px-2">{{
|
||||
contract.status
|
||||
}}</span>
|
||||
</td>
|
||||
<td class="py-3 px-4 text-center">
|
||||
{{ new Date(contract.appointment).toDateString() }}
|
||||
</td>
|
||||
<td class="py-3 px-4 text-center">{{ contract.notes }}</td>
|
||||
<td class="text-left py-2">
|
||||
<RouterLink to="/contract?id=TESTID">
|
||||
<button
|
||||
class="bg-blue-500 text-white active:bg-emerald-600 font-bold uppercase text-xs px-4 py-2 rounded shadow hover:shadow-md outline-none focus:outline-none mr-1 mb-1 ease-linear transition-all duration-150"
|
||||
type="button">
|
||||
View
|
||||
</button>
|
||||
</RouterLink>
|
||||
<button
|
||||
class="bg-blue-500 text-white active:bg-emerald-600 font-bold uppercase text-xs px-4 py-2 rounded shadow hover:shadow-md outline-none focus:outline-none mr-1 mb-1 ease-linear transition-all duration-150"
|
||||
type="button">
|
||||
View
|
||||
v-if="contract.registered"
|
||||
class="bg-emerald-500 text-white active:bg-emerald-600 font-bold uppercase text-xs px-4 py-2 rounded shadow hover:shadow-md outline-none focus:outline-none mr-1 mb-1 ease-linear transition-all duration-150"
|
||||
type="button"
|
||||
@click="
|
||||
selectContract(contract.id);
|
||||
openModal('register')
|
||||
">
|
||||
Anmelden
|
||||
</button>
|
||||
</RouterLink>
|
||||
<button
|
||||
class="bg-emerald-500 text-white active:bg-emerald-600 font-bold uppercase text-xs px-4 py-2 rounded shadow hover:shadow-md outline-none focus:outline-none mr-1 mb-1 ease-linear transition-all duration-150"
|
||||
type="button"
|
||||
@click="openDialog('register')">
|
||||
Anmelden
|
||||
</button>
|
||||
<button
|
||||
class="bg-red-500 text-white active:bg-red-600 font-bold uppercase text-xs px-4 py-2 rounded shadow hover:shadow-md outline-none focus:outline-none mr-1 mb-1 ease-linear transition-all duration-150"
|
||||
type="button"
|
||||
@click="openDialog('deregister')">
|
||||
Abmelden
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<button
|
||||
v-if="!contract.registered"
|
||||
class="bg-red-500 text-white active:bg-red-600 font-bold uppercase text-xs px-4 py-2 rounded shadow hover:shadow-md outline-none focus:outline-none mr-1 mb-1 ease-linear transition-all duration-150"
|
||||
type="button"
|
||||
@click="
|
||||
selectContract(contract.id);
|
||||
openModal('deregister')
|
||||
">
|
||||
Abmelden
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -74,11 +84,6 @@ import Navbar from '../components/Navbar.vue'
|
||||
import { mapActions } from 'vuex'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
dialog: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
openContracts() {
|
||||
return this.$store.state.contracts.openContracts
|
||||
@@ -88,9 +93,10 @@ export default {
|
||||
this.fetchOpenContracts()
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['fetchOpenContracts']),
|
||||
openDialog(name) {
|
||||
this.dialog = name
|
||||
...mapActions(['fetchOpenContracts', 'openModal']),
|
||||
selectContract(ID) {
|
||||
console.log(ID)
|
||||
this.$store.commit('setSelectedContract', ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user