PersonalSettingOutOfOffice.vue 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. <!-- Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/ -->
  2. <script setup lang="ts">
  3. import { isEqual } from 'lodash-es'
  4. import { storeToRefs } from 'pinia'
  5. import { reactive, computed, watch } from 'vue'
  6. import {
  7. NotificationTypes,
  8. useNotifications,
  9. } from '#shared/components/CommonNotifications/index.ts'
  10. import Form from '#shared/components/Form/Form.vue'
  11. import type {
  12. FormSubmitData,
  13. FormSchemaField,
  14. FormFieldValue,
  15. } from '#shared/components/Form/types.ts'
  16. import { useForm } from '#shared/components/Form/useForm.ts'
  17. import { defineFormSchema } from '#shared/form/defineFormSchema.ts'
  18. import type { OutOfOfficeInput } from '#shared/graphql/types.ts'
  19. import { convertToGraphQLId } from '#shared/graphql/utils.ts'
  20. import { MutationHandler } from '#shared/server/apollo/handler/index.ts'
  21. import { useSessionStore } from '#shared/stores/session.ts'
  22. import CommonButton from '#desktop/components/CommonButton/CommonButton.vue'
  23. import LayoutContent from '#desktop/components/layout/LayoutContent.vue'
  24. import { useBreadcrumb } from '../composables/useBreadcrumb.ts'
  25. import { useUserCurrentOutOfOfficeMutation } from '../graphql/mutations/userCurrentOutOfOffice.api.ts'
  26. import type { OutOfOfficeFormData } from '../types/out-of-office.ts'
  27. const { user } = storeToRefs(useSessionStore())
  28. const { form, isDisabled, onChangedField, formReset, values, isDirty } =
  29. useForm()
  30. const schema = defineFormSchema([
  31. {
  32. isLayout: true,
  33. component: 'FormGroup',
  34. children: [
  35. {
  36. type: 'text',
  37. name: 'text',
  38. label: __('Reason for absence'),
  39. placeholder: __('e.g. Easter holiday'),
  40. },
  41. {
  42. type: 'date',
  43. name: 'date_range',
  44. label: __('Start and end date'),
  45. props: {
  46. clearable: true,
  47. range: true,
  48. },
  49. },
  50. {
  51. type: 'agent',
  52. name: 'replacement_id',
  53. label: __('Replacement agent'),
  54. props: {
  55. clearable: true,
  56. belongsToObjectField: 'outOfOfficeReplacement',
  57. exceptUserInternalId: user.value?.internalId,
  58. },
  59. },
  60. {
  61. type: 'toggle',
  62. name: 'enabled',
  63. label: __('Active'),
  64. props: {
  65. variants: {
  66. true: __('Active'),
  67. false: __('Inactive'),
  68. },
  69. },
  70. },
  71. ],
  72. },
  73. ])
  74. const initialFormValues = computed<OutOfOfficeFormData>((oldValues) => {
  75. const values: OutOfOfficeFormData = {
  76. text: user.value?.preferences?.out_of_office_text,
  77. replacement_id: user.value?.outOfOfficeReplacement?.internalId,
  78. enabled: !!user.value?.outOfOffice,
  79. }
  80. if (user.value?.outOfOfficeStartAt && user.value?.outOfOfficeEndAt) {
  81. values.date_range = [
  82. user.value?.outOfOfficeStartAt,
  83. user.value?.outOfOfficeEndAt,
  84. ]
  85. }
  86. if (oldValues && isEqual(values, oldValues)) {
  87. return oldValues
  88. }
  89. return values
  90. })
  91. watch(initialFormValues, (newValues) => {
  92. // No reset needed when the form has already the correct state.
  93. if (isEqual(values.value, newValues) && !isDirty.value) return
  94. formReset({ values: newValues, object: user.value! })
  95. })
  96. const buildFormChangesHash = (enabled: boolean) => {
  97. return {
  98. replacement_id: { required: enabled },
  99. date_range: { required: enabled },
  100. }
  101. }
  102. const formChangeFields = reactive<Record<string, Partial<FormSchemaField>>>(
  103. buildFormChangesHash(initialFormValues.value.enabled),
  104. )
  105. onChangedField('enabled', (newValue: FormFieldValue) => {
  106. Object.assign(formChangeFields, buildFormChangesHash(!!newValue))
  107. })
  108. const { breadcrumbItems } = useBreadcrumb(__('Out of Office'))
  109. const formDataToInput = (
  110. formData: FormSubmitData<OutOfOfficeFormData>,
  111. ): OutOfOfficeInput => {
  112. const replacementId = formData.replacement_id
  113. ? convertToGraphQLId('User', formData.replacement_id)
  114. : undefined
  115. return {
  116. enabled: formData.enabled,
  117. text: formData.text,
  118. startAt: formData.date_range?.at(0),
  119. endAt: formData.date_range?.at(1),
  120. replacementId,
  121. }
  122. }
  123. const { notify } = useNotifications()
  124. const showSuccessNotification = () => {
  125. notify({
  126. id: 'out-of-office-saved',
  127. type: NotificationTypes.Success,
  128. message: __('Out of Office settings have been saved successfully'),
  129. })
  130. }
  131. const outOfOfficeMutation = new MutationHandler(
  132. useUserCurrentOutOfOfficeMutation(),
  133. {
  134. errorNotificationMessage: __('Out of Office settings could not be saved.'),
  135. },
  136. )
  137. const submitForm = async (formData: FormSubmitData<OutOfOfficeFormData>) => {
  138. return outOfOfficeMutation
  139. .send({ input: formDataToInput(formData) })
  140. .then(() => showSuccessNotification)
  141. }
  142. </script>
  143. <template>
  144. <LayoutContent :breadcrumb-items="breadcrumbItems" width="narrow">
  145. <div class="mb-4">
  146. <Form
  147. ref="form"
  148. :initial-values="initialFormValues"
  149. :initial-entity-object="user!"
  150. :schema="schema"
  151. :change-fields="formChangeFields"
  152. @submit="submitForm($event as FormSubmitData<OutOfOfficeFormData>)"
  153. >
  154. <template #after-fields>
  155. <div class="mt-5 flex items-center justify-end gap-2">
  156. <CommonButton
  157. variant="submit"
  158. type="submit"
  159. size="medium"
  160. :disabled="isDisabled"
  161. >
  162. {{ $t('Save Out of Office') }}
  163. </CommonButton>
  164. </div>
  165. </template>
  166. </Form>
  167. </div>
  168. </LayoutContent>
  169. </template>