Skip to content

Commit

Permalink
feat: improve colleague info page and set jobs user props logic
Browse files Browse the repository at this point in the history
Signed-off-by: Alexander Trost <[email protected]>
  • Loading branch information
galexrt committed Dec 3, 2024
1 parent 76a73e8 commit 9595e30
Show file tree
Hide file tree
Showing 69 changed files with 2,884 additions and 1,703 deletions.
429 changes: 208 additions & 221 deletions app/components/documents/DocumentList.vue

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions app/components/documents/DocumentView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ defineShortcuts({
class="flex-1"
:text="`${$t('common.pin', 1)}/ ${$t('common.unpin')}`"
>
<UButton block @click="togglePin(documentId, !doc.pinned)">
<UButton block class="flex-1 flex-col" @click="togglePin(documentId, !doc.pinned)">
<template v-if="!doc.pinned">
<UIcon name="i-mdi-pin" class="size-5" />
{{ $t('common.pin') }}
Expand All @@ -369,8 +369,8 @@ defineShortcuts({
:shortcuts="['D', 'R']"
>
<UButton
class="flex-1 flex-col"
block
class="flex-1 flex-col"
icon="i-mdi-frequently-asked-questions"
@click="openRequestsModal"
>
Expand All @@ -380,8 +380,8 @@ defineShortcuts({

<UButton
v-if="can('DocStoreService.SetDocumentReminder').value"
class="flex-1 flex-col"
block
class="flex-1 flex-col"
icon="i-mdi-reminder"
@click="
modal.open(DocumentReminderModal, {
Expand All @@ -400,8 +400,8 @@ defineShortcuts({
can('DocStoreService.ChangeDocumentOwner').value &&
checkDocAccess(access, doc?.creator, AccessLevel.EDIT, 'DocStoreService.ChangeDocumentOwner')
"
class="flex-1 flex-col"
block
class="flex-1 flex-col"
:disabled="doc?.creatorId === activeChar?.userId"
icon="i-mdi-creation"
@click="
Expand All @@ -418,8 +418,8 @@ defineShortcuts({
can('DocStoreService.DeleteDocument').value &&
checkDocAccess(access, doc.creator, AccessLevel.EDIT, 'DocStoreService.DeleteDocument')
"
class="flex-1 flex-col"
block
class="flex-1 flex-col"
:color="!doc.deletedAt ? 'red' : undefined"
:icon="!doc.deletedAt ? 'i-mdi-trash-can' : 'i-mdi-restore'"
@click="
Expand Down
9 changes: 5 additions & 4 deletions app/components/jobs/colleagues/ColleagueInfoPopover.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import DataErrorBlock from '~/components/partials/data/DataErrorBlock.vue';
import GenericTime from '~/components/partials/elements/GenericTime.vue';
import type { ClassProp } from '~/typings';
import type { Colleague } from '~~/gen/ts/resources/jobs/colleagues';
import ColleagueName from './ColleagueName.vue';
const props = withDefaults(
defineProps<{
Expand Down Expand Up @@ -94,7 +95,7 @@ watchOnce(opened, async () => {
</template>

<USkeleton v-if="!user && loading" class="h-8 w-[125px]" />
<span v-else class="truncate" :class="textClass"> {{ user?.firstname }} {{ user?.lastname }} </span>
<span v-else class="truncate" :class="textClass"> <ColleagueName :colleague="user" /> </span>
<slot name="after" />
</UButton>

Expand Down Expand Up @@ -159,7 +160,7 @@ watchOnce(opened, async () => {
params: { id: user.userId ?? 0 },
}"
>
{{ user.firstname }} {{ user.lastname }}
<ColleagueName :colleague="user" />
</UButton>
<UButton
v-else-if="can('CitizenStoreService.ListCitizens').value"
Expand All @@ -170,9 +171,9 @@ watchOnce(opened, async () => {
params: { id: user.userId ?? 0 },
}"
>
{{ user.firstname }} {{ user.lastname }}
<ColleagueName :colleague="user" />
</UButton>
<UButton v-else variant="link" :padded="false"> {{ user.firstname }} {{ user.lastname }} </UButton>
<UButton v-else variant="link" :padded="false"> <ColleagueName :colleague="user" /> </UButton>

<p v-if="user.jobLabel" class="text-sm font-normal">
<span class="font-semibold">{{ $t('common.job') }}:</span>
Expand Down
16 changes: 16 additions & 0 deletions app/components/jobs/colleagues/ColleagueName.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<script lang="ts" setup>
import type { Colleague } from '~~/gen/ts/resources/jobs/colleagues';
defineProps<{
colleague: Colleague;
birthday?: boolean;
}>();
</script>

<template>
<span>
{{ colleague.props?.namePrefix ? colleague.props?.namePrefix + ' ' : '' }}{{ colleague.firstname }}
{{ colleague.lastname }} {{ colleague.props?.nameSuffix ? colleague.props?.nameSuffix + ' ' : '' }}
<template v-if="birthday"> ({{ colleague.dateofbirth }}) </template>
</span>
</template>
51 changes: 35 additions & 16 deletions app/components/jobs/colleagues/ColleagueSetLabels.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useNotificatorStore } from '~/store/notificator';
import type { JobsUserProps } from '~~/gen/ts/resources/jobs/colleagues';
import type { Labels } from '~~/gen/ts/resources/jobs/labels';
import { NotificationType } from '~~/gen/ts/resources/notifications/notifications';
import type { GetColleagueLabelsResponse } from '~~/gen/ts/services/jobs/jobs';
import type { GetColleagueLabelsResponse, SetJobsUserPropsResponse } from '~~/gen/ts/services/jobs/jobs';
const props = defineProps<{
modelValue?: Labels;
Expand All @@ -14,6 +14,7 @@ const props = defineProps<{
const emit = defineEmits<{
(e: 'update:modelValue', labels: Labels | undefined): void;
(e: 'refresh'): void;
}>();
const { attr, can } = useAuth();
Expand All @@ -40,6 +41,7 @@ async function getColleagueLabels(): Promise<GetColleagueLabelsResponse> {
const changed = ref(false);
const schema = z.object({
reason: z.string().min(3).max(255),
labels: z
.object({
id: z.string(),
Expand All @@ -48,17 +50,16 @@ const schema = z.object({
})
.array()
.max(10),
reason: z.string().min(3).max(255),
});
type Schema = z.output<typeof schema>;
const state = reactive<Schema>({
labels: labels.value?.list !== undefined ? labels.value.list.slice() : [],
reason: '',
labels: labels.value?.list.map((l) => ({ ...l, selected: true })) ?? [],
});
async function setUserJobProp(userId: number, values: Schema): Promise<void> {
async function setUserJobProp(userId: number, values: Schema): Promise<SetJobsUserPropsResponse> {
const jobsUserProps: JobsUserProps = {
userId: userId,
job: '',
Expand All @@ -74,14 +75,18 @@ async function setUserJobProp(userId: number, values: Schema): Promise<void> {
});
const { response } = await call;
changed.value = false;
state.reason = '';
emit('refresh');
state.labels = labels.value?.list.map((l) => ({ ...l, selected: true })) ?? [];
notifications.add({
title: { key: 'notifications.action_successfull.title', parameters: {} },
description: { key: 'notifications.action_successfull.content', parameters: {} },
type: NotificationType.SUCCESS,
});
labels.value = response.props?.labels;
state.reason = '';
return response;
} catch (e) {
handleGRPCError(e as RpcError);
throw e;
Expand All @@ -92,7 +97,6 @@ const canSubmit = ref(true);
const onSubmitThrottle = useThrottleFn(async (event: FormSubmitEvent<Schema>) => {
canSubmit.value = false;
await setUserJobProp(props.userId, event.data).finally(() => useTimeoutFn(() => (canSubmit.value = true), 400));
changed.value = false;
}, 1000);
watch(props, () => (state.labels = labels.value?.list !== undefined ? labels.value?.list.slice() : []));
Expand All @@ -108,17 +112,28 @@ watch(state, () => {
}
});
onMounted(() => {
state.labels = labels.value?.list.map((l) => ({ ...l, selected: true })) ?? [];
});
const editing = ref(false);
</script>

<template>
<UForm :schema="schema" :state="state" class="flex flex-col gap-2" @submit="onSubmitThrottle">
<UForm :schema="schema" :state="state" class="flex flex-1 flex-col gap-2" @submit="onSubmitThrottle">
<p v-if="!state.labels.length" class="text-sm leading-6">
{{ $t('common.none', [$t('common.label', 2)]) }}
</p>
<template v-else>
<div>
<UButton v-if="!editing" icon="i-mdi-pencil" @click="editing = true" />
<UButton
v-else
icon="i-mdi-cancel"
color="red"
@click="
state.labels = labels?.list.map((l) => ({ ...l, selected: true })) ?? [];
editing = false;
"
/>
</div>

<div class="flex max-w-72 flex-row flex-wrap gap-1">
<UBadge
v-for="(attribute, idx) in state.labels"
Expand All @@ -133,7 +148,7 @@ onMounted(() => {
</span>

<UButton
v-if="canDo.set"
v-if="canDo.set && editing"
variant="link"
icon="i-mdi-close"
:padded="false"
Expand All @@ -152,7 +167,7 @@ onMounted(() => {
</div>
</template>

<UFormGroup name="labels">
<UFormGroup v-if="editing" name="labels">
<ClientOnly>
<USelectMenu
v-model="state.labels"
Expand Down Expand Up @@ -196,9 +211,13 @@ onMounted(() => {
<UInput v-model="state.reason" type="text" />
</UFormGroup>

<UButton type="submit" block icon="i-mdi-content-save" :disabled="!canSubmit" :loading="!canSubmit">
{{ $t('common.save') }}
</UButton>
<UButtonGroup>
<UButton type="submit" icon="i-mdi-content-save" :disabled="!canSubmit" :loading="!canSubmit">
{{ $t('common.save') }}
</UButton>

<UButton icon="i-mdi-cancel" color="red" @click="state.labels = labels" />
</UButtonGroup>
</template>
</UForm>
</template>
130 changes: 130 additions & 0 deletions app/components/jobs/colleagues/ColleagueSetName.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<script lang="ts" setup>
import type { FormSubmitEvent } from '#ui/types';
import { z } from 'zod';
import { useNotificatorStore } from '~/store/notificator';
import { NotificationType } from '~~/gen/ts/resources/notifications/notifications';
import type { SetJobsUserPropsResponse } from '~~/gen/ts/services/jobs/jobs';
const props = defineProps<{
namePrefix: string | undefined;
nameSuffix: string | undefined;
userId: number;
}>();
const emit = defineEmits<{
(e: 'update:namePrefix', value?: string): void;
(e: 'update:nameSuffix', value?: string): void;
(e: 'refresh'): void;
}>();
const { namePrefix, nameSuffix } = useVModels(props, emit);
const notifications = useNotificatorStore();
const schema = z.object({
reason: z.string().min(3).max(255),
prefix: z.string().max(12).optional(),
suffix: z.string().max(12).optional(),
});
type Schema = z.output<typeof schema>;
const state = reactive<Schema>({
reason: '',
prefix: props.namePrefix ?? '',
suffix: props.nameSuffix ?? '',
});
watch(props, () => {
state.prefix = props.namePrefix ?? '';
state.suffix = props.nameSuffix ?? '';
});
const changed = ref(false);
async function setJobsUserNote(values: Schema): Promise<undefined | SetJobsUserPropsResponse> {
try {
const call = getGRPCJobsClient().setJobsUserProps({
reason: values.reason,
props: {
userId: props.userId,
job: '',
namePrefix: values.prefix,
nameSuffix: values.suffix,
},
});
const { response } = await call;
editing.value = false;
changed.value = false;
state.reason = '';
emit('refresh');
notifications.add({
title: { key: 'notifications.action_successfull.title', parameters: {} },
description: { key: 'notifications.action_successfull.content', parameters: {} },
type: NotificationType.SUCCESS,
});
return response;
} catch (e) {
handleGRPCError(e as RpcError);
throw e;
}
}
const canSubmit = ref(true);
const onSubmitThrottle = useThrottleFn(async (event: FormSubmitEvent<Schema>) => {
canSubmit.value = false;
await setJobsUserNote(event.data).finally(() => useTimeoutFn(() => (canSubmit.value = true), 400));
}, 1000);
watch(state, () => {
if (state.prefix === namePrefix.value && state.suffix === nameSuffix.value) {
changed.value = false;
} else {
changed.value = true;
}
});
const editing = ref(false);
</script>

<template>
<UForm :schema="schema" :state="state" class="flex flex-1 flex-col gap-2" @submit="onSubmitThrottle">
<div>
<UButton v-if="!editing" icon="i-mdi-pencil" @click="editing = true" />
<UButton
v-else
icon="i-mdi-cancel"
color="red"
@click="
state.prefix = namePrefix;
state.suffix = nameSuffix;
editing = false;
"
/>
</div>

<div class="flex flex-col gap-2 sm:flex-row">
<UFormGroup name="prefix" :label="$t('common.prefix')">
<UInput v-if="editing" v-model="state.prefix" type="text" />
<span v-else>{{ namePrefix ?? $t('common.na') }}</span>
</UFormGroup>
<UFormGroup name="suffix" :label="$t('common.suffix')">
<UInput v-if="editing" v-model="state.suffix" type="text" />
<span v-else>{{ nameSuffix ?? $t('common.na') }}</span>
</UFormGroup>
</div>

<template v-if="changed">
<UFormGroup name="reason" :label="$t('common.reason')" required>
<UInput v-model="state.reason" type="text" />
</UFormGroup>

<UButton type="submit" block icon="i-mdi-content-save" :disabled="!canSubmit" :loading="!canSubmit">
{{ $t('common.save') }}
</UButton>
</template>
</UForm>
</template>
Loading

0 comments on commit 9595e30

Please sign in to comment.