First work on transfer services

This commit is contained in:
Ferdinand Thiessen 2021-11-21 17:51:10 +01:00
parent 8b6fd67f1d
commit ea64568e2b
6 changed files with 162 additions and 29 deletions

View File

@ -23,20 +23,20 @@
}, },
"devDependencies": { "devDependencies": {
"@flaschengeist/types": "^1.0.0-alpha.5", "@flaschengeist/types": "^1.0.0-alpha.5",
"@quasar/app": "^3.2.2", "@quasar/app": "^3.2.3",
"quasar": "^2.3.2", "quasar": "^2.3.3",
"axios": "^0.24.0", "axios": "^0.24.0",
"prettier": "^2.4.1", "prettier": "^2.4.1",
"typescript": "^4.4.4", "typescript": "^4.4.4",
"pinia": "^2.0.3", "pinia": "^2.0.4",
"@typescript-eslint/eslint-plugin": "^5.4.0", "@typescript-eslint/eslint-plugin": "^5.4.0",
"@typescript-eslint/parser": "^5.4.0", "@typescript-eslint/parser": "^5.4.0",
"eslint": "^8.2.0", "eslint": "^8.3.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-vue": "^8.0.3" "eslint-plugin-vue": "^8.1.1"
}, },
"peerDependencies": { "peerDependencies": {
"@flaschengeist/api": "^1.0.0-alpha.2", "@flaschengeist/api": "^1.0.0-alpha.4",
"@flaschengeist/users": "^1.0.0-alpha.1" "@flaschengeist/users": "^1.0.0-alpha.1"
}, },
"prettier": { "prettier": {

1
src/api.d.ts vendored
View File

@ -27,6 +27,7 @@ declare namespace FG {
comment?: string; comment?: string;
services: Array<Service>; services: Array<Service>;
required_services: number; required_services: number;
locked: boolean;
} }
interface JobType { interface JobType {
id: number; id: number;

View File

@ -27,8 +27,29 @@
> >
</q-select> </q-select>
<div class="row col-12 justify-end"> <div class="row col-12 justify-end">
<q-btn v-if="canEnroll" flat color="primary" label="Eintragen" @click="enrollForJob" /> <q-btn
<q-btn v-if="isEnrolled" flat color="negative" label="Austragen" @click="signOutFromJob" /> v-if="!modelValue.locked && !isEnrolled && !isFull"
flat
color="primary"
label="Eintragen"
@click="enrollForJob"
/>
<q-btn v-if="isEnrolled && !modelValue.locked" flat color="secondary" label="Optionen">
<q-menu auto-close>
<q-list style="min-width: 100px">
<q-item v-if="!isFull && canInvite" clickable @click="invite">
<q-item-section>Einladen</q-item-section>
</q-item>
<q-item clickable @click="transfer">
<q-item-section>Tauschen</q-item-section>
</q-item>
<q-separator />
<q-item clickable @click="signOutFromJob">
<q-item-section class="text-negative">Austragen</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
</div> </div>
</div> </div>
</q-card> </q-card>
@ -36,9 +57,10 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, onBeforeMount, computed, PropType } from 'vue'; import { defineComponent, onBeforeMount, computed, PropType } from 'vue';
import { useQuasar } from 'quasar'; import { date, useQuasar } from 'quasar';
import { asHour, useMainStore, useUserStore } from '@flaschengeist/api'; import { asHour, useMainStore, useUserStore } from '@flaschengeist/api';
import { useEventStore } from '../../../store'; import { useEventStore } from '../../../store';
import TransferInviteDialog from './TransferInviteDialog.vue';
export default defineComponent({ export default defineComponent({
name: 'JobSlot', name: 'JobSlot',
@ -72,12 +94,20 @@ export default defineComponent({
) !== -1 ) !== -1
); );
const canEnroll = computed(() => { const isFull = computed(
const is = isEnrolled.value; () =>
let sum = 0; props.modelValue.services.map((s) => s.value).reduce((p, c) => p + c, 0) >=
props.modelValue.services.forEach((s) => (sum += s.value)); props.modelValue.required_services
return sum < props.modelValue.required_services && !is; );
});
const canInvite = computed(
() =>
(props.modelValue.end || props.modelValue.start) >
date.subtractFromDate(
date.buildDate({ hours: 0, minutes: 0, seconds: 0, milliseconds: 0 }),
{ days: 1 }
)
);
async function enrollForJob() { async function enrollForJob() {
const newService: FG.Service = { const newService: FG.Service = {
@ -86,7 +116,9 @@ export default defineComponent({
value: 1, value: 1,
}; };
try { try {
const job = await store.updateJob(props.eventId, props.modelValue.id, { user: newService }); await store.assignToJob(props.modelValue.id, newService);
const job = Object.assign({}, props.modelValue)
job.services.push(newService)
emit('update:modelValue', job); emit('update:modelValue', job);
} catch (error) { } catch (error) {
console.warn(error); console.warn(error);
@ -107,9 +139,9 @@ export default defineComponent({
value: -1, value: -1,
}; };
try { try {
const job = await store.updateJob(props.eventId, props.modelValue.id, { await store.assignToJob(props.modelValue.id, newService);
user: newService, const job = Object.assign({}, props.modelValue)
}); job.services.push(newService)
emit('update:modelValue', job); emit('update:modelValue', job);
} catch (error) { } catch (error) {
console.warn(error); console.warn(error);
@ -124,12 +156,24 @@ export default defineComponent({
} }
} }
function invite(isInvite = true) {
quasar.dialog({
component: TransferInviteDialog,
componentProps: {
invite: isInvite,
job: props.modelValue,
},
});
}
return { return {
availableUsers, canInvite,
enrollForJob, enrollForJob,
isEnrolled, isEnrolled,
isFull,
invite: () => invite(true),
signOutFromJob, signOutFromJob,
canEnroll, transfer: () => invite(false),
userDisplay, userDisplay,
asHour, asHour,
}; };

View File

@ -0,0 +1,84 @@
<template>
<!-- notice dialogRef here -->
<q-dialog ref="dialogRef" @hide="onDialogHide">
<q-card class="q-dialog-plugin">
<q-card-section>
<div v-if="isInvite" class="text-h6">Zum Dienst einladen</div>
<div v-else class="text-h6">Dienst tauschen</div>
</q-card-section>
<q-separator />
<q-card-section>
<q-select
v-model="invitees"
filled
:options="otherUsers"
:option-label="(opt) => opt.display_name"
:multiple="isInvite"
use-chips
stack-label
label="Dienste"
>
</q-select>
</q-card-section>
<!-- buttons example -->
<q-card-actions align="right">
<q-btn color="primary" label="Ok" @click="invite" />
<q-btn color="primary" label="Abbrechen" @click="onDialogCancel" />
</q-card-actions>
</q-card>
</q-dialog>
</template>
<script lang="ts">
import { useMainStore, useUserStore } from '@flaschengeist/api';
import { useEventStore } from '../../../store';
import { useDialogPluginComponent } from 'quasar';
import { PropType, computed, defineComponent, ref } from 'vue';
export default defineComponent({
props: {
isInvite: {
type: Boolean,
default: true,
},
job: {
required: true,
type: Object as PropType<FG.Job>,
},
},
emits: [...useDialogPluginComponent.emits],
setup(props) {
const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } = useDialogPluginComponent();
const userStore = useUserStore();
const mainStore = useMainStore();
const store = useEventStore();
const invitees = ref([] as FG.User[]);
const otherUsers = computed(() =>
userStore.users.filter(
(u) =>
u.userid !== mainStore.currentUser.userid &&
props.job.services.findIndex((s) => s.userid === u.userid) === -1
)
);
function invite() {
store
.sendInvite(props.job, invitees.value, !props.isInvite)
.then(() => onDialogOK())
.catch(() => onDialogCancel());
}
return {
invite,
invitees,
otherUsers,
dialogRef,
onDialogHide,
onDialogCancel,
};
},
});
</script>

View File

@ -13,4 +13,8 @@ export const PERMISSIONS = {
ASSIGN: 'events_assign', ASSIGN: 'events_assign',
// Can assign other users to jobs // Can assign other users to jobs
ASSIGN_OTHER: 'events_assign_other', ASSIGN_OTHER: 'events_assign_other',
// Can see users assigned as backup
SEE_BACKUP: 'events_see_backup',
// Can lock jobs, no further services can be assigned or unassigned
LOCK_JOBS: 'events_lock_jobs',
}; };

View File

@ -138,14 +138,8 @@ export const useEventStore = defineStore({
} }
}, },
async updateJob(eventId: number, jobId: number, service: FG.Service | UserService) { async assignToJob(jobId: number, service: FG.Service) {
try { return api.post<FG.Job>(`/events/jobs/${jobId}/assign`, service);
const { data } = await api.put<FG.Job>(`/events/${eventId}/jobs/${jobId}`, service);
fixJob(data);
return data;
} catch (error) {
throw error;
}
}, },
async addEvent(event: FG.Event) { async addEvent(event: FG.Event) {
@ -161,5 +155,11 @@ export const useEventStore = defineStore({
return data; return data;
} }
}, },
async sendInvite(job: FG.Job, invitees: FG.User[], transfer = false) {
await Promise.resolve()
console.log(job, invitees, transfer)
return Promise.resolve()
}
}, },
}); });