@tager/admin-banners 0.3.6 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ import { Ref, SetupContext } from '@vue/composition-api';
2
+ import { Nullable, ResourceRef } from '@tager/admin-services';
3
+ import { ZoneFields } from '../typings/zones';
4
+ import { BannerFormValues } from '../typings/banners';
5
+ export declare function useFetchZoneFields({ context, values, }: {
6
+ context: SetupContext;
7
+ values: Ref<BannerFormValues>;
8
+ }): ResourceRef<Nullable<ZoneFields>>;
package/dist/index.esm.js CHANGED
@@ -2,6 +2,7 @@ import { request, useResource, useResourceDelete, createId, convertRequestErrorT
2
2
  import { defineComponent, onMounted, computed, ref, watch } from '@vue/composition-api';
3
3
  import { useDataTable, getFilterParamAsStringArray, getFilterParamAsString, getFilterParams, useTranslation, FormFooter } from '@tager/admin-ui';
4
4
  import { compile } from 'path-to-regexp';
5
+ import { universalFieldUtils, DynamicField } from '@tager/admin-dynamic-field';
5
6
 
6
7
  const EN = {
7
8
  home: 'Home',
@@ -89,6 +90,9 @@ const RU = {
89
90
  function getZones(params) {
90
91
  return request.get({ path: '/admin/adv/zones', params });
91
92
  }
93
+ function getZoneFields(zoneId) {
94
+ return request.get({ path: `/admin/adv/zones/${zoneId}` });
95
+ }
92
96
  /** Banners **/
93
97
  function getBanners(params) {
94
98
  return request.get({ path: '/admin/adv', params });
@@ -3248,11 +3252,34 @@ function useFetchBanner({ context, bannerId, isCreation, }) {
3248
3252
  return resource;
3249
3253
  }
3250
3254
 
3255
+ function useFetchZoneFields({ context, values, }) {
3256
+ const zoneId = computed(() => { var _a, _b; return (_b = (_a = values.value.bannerZone) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : ''; });
3257
+ const [fetchZoneFields, resource] = useResource({
3258
+ fetchResource: () => getZoneFields(zoneId.value),
3259
+ initialValue: null,
3260
+ context,
3261
+ resourceName: 'Zone Fields',
3262
+ });
3263
+ onMounted(() => {
3264
+ if (!zoneId.value) {
3265
+ return;
3266
+ }
3267
+ fetchZoneFields();
3268
+ });
3269
+ watch(zoneId, () => {
3270
+ if (!zoneId.value) {
3271
+ return;
3272
+ }
3273
+ fetchZoneFields();
3274
+ });
3275
+ return resource;
3276
+ }
3277
+
3251
3278
  function convertBannerToFormValues(banner, zonesOptionList) {
3252
3279
  var _a, _b, _c, _d, _e, _f, _g;
3253
3280
  const foundZone = zonesOptionList.find(({ value }) => value === (banner === null || banner === void 0 ? void 0 : banner.bannerZone));
3254
3281
  return {
3255
- priority: (_a = banner === null || banner === void 0 ? void 0 : banner.priority) !== null && _a !== void 0 ? _a : 1,
3282
+ priority: String((_a = banner === null || banner === void 0 ? void 0 : banner.priority) !== null && _a !== void 0 ? _a : 1),
3256
3283
  link: (_b = banner === null || banner === void 0 ? void 0 : banner.link) !== null && _b !== void 0 ? _b : '',
3257
3284
  image: (banner === null || banner === void 0 ? void 0 : banner.image) ? { id: createId(), file: banner.image } : null,
3258
3285
  bannerZone: foundZone !== null && foundZone !== void 0 ? foundZone : null,
@@ -3261,16 +3288,20 @@ function convertBannerToFormValues(banner, zonesOptionList) {
3261
3288
  dateEnd: (_e = banner === null || banner === void 0 ? void 0 : banner.dateEnd) !== null && _e !== void 0 ? _e : '',
3262
3289
  disabled: (_f = banner === null || banner === void 0 ? void 0 : banner.disabled) !== null && _f !== void 0 ? _f : false,
3263
3290
  comment: (_g = banner === null || banner === void 0 ? void 0 : banner.comment) !== null && _g !== void 0 ? _g : '',
3291
+ fields: [],
3264
3292
  };
3265
3293
  }
3266
3294
  function convertBannerFormValuesToPayload(values) {
3267
3295
  var _a, _b, _c, _d;
3268
- return Object.assign(Object.assign({}, values), { priority: values.priority ? Number(values.priority) : 1, dateStart: values.dateStart ? values.dateStart : null, dateEnd: values.dateEnd ? values.dateEnd : null, image: (_b = (_a = values.image) === null || _a === void 0 ? void 0 : _a.file.id) !== null && _b !== void 0 ? _b : null, bannerZone: (_d = (_c = values.bannerZone) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : '' });
3296
+ return Object.assign(Object.assign({}, values), { priority: values.priority ? Number(values.priority) : 1, dateStart: values.dateStart ? values.dateStart : null, dateEnd: values.dateEnd ? values.dateEnd : null, image: (_b = (_a = values.image) === null || _a === void 0 ? void 0 : _a.file.id) !== null && _b !== void 0 ? _b : null, bannerZone: (_d = (_c = values.bannerZone) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : '', fields: values.fields.map((field) => ({
3297
+ name: field.config.name,
3298
+ value: universalFieldUtils.getOutgoingValue(field),
3299
+ })) });
3269
3300
  }
3270
3301
 
3271
3302
  var script$2 = defineComponent({
3272
3303
  name: 'BannerForm',
3273
- components: { FormFooter },
3304
+ components: { FormFooter, DynamicField },
3274
3305
  setup(props, context) {
3275
3306
  const bannerId = computed(() => context.root.$route.params.bannerId);
3276
3307
  const isCreation = computed(() => bannerId.value === 'create');
@@ -3293,6 +3324,15 @@ var script$2 = defineComponent({
3293
3324
  watch([banner, zones], () => {
3294
3325
  values.value = convertBannerToFormValues(banner.value, zonesOptionList.value);
3295
3326
  });
3327
+ /** Zone Fields **/
3328
+ const { loading: isZoneFieldsLoading, data: zoneFields, } = useFetchZoneFields({ context, values });
3329
+ watch(zoneFields, () => {
3330
+ var _a, _b;
3331
+ values.value.fields = ((_b = (_a = zoneFields.value) === null || _a === void 0 ? void 0 : _a.fields) !== null && _b !== void 0 ? _b : []).map((fieldConfig, index) => {
3332
+ var _a;
3333
+ return universalFieldUtils.createFormField(fieldConfig, banner.value ? (_a = banner.value.fields[index].value) !== null && _a !== void 0 ? _a : null : null);
3334
+ });
3335
+ });
3296
3336
  const submitForm = (event) => {
3297
3337
  isSubmitting.value = true;
3298
3338
  const body = convertBannerFormValuesToPayload(values.value);
@@ -3334,7 +3374,9 @@ var script$2 = defineComponent({
3334
3374
  isSubmitting.value = false;
3335
3375
  });
3336
3376
  };
3337
- const isContentLoading = computed(() => isBannerLoading.value || isZonesLoading.value);
3377
+ const isContentLoading = computed(() => isBannerLoading.value ||
3378
+ isZonesLoading.value ||
3379
+ isZoneFieldsLoading.value);
3338
3380
  return {
3339
3381
  isCreation,
3340
3382
  isContentLoading,
@@ -3527,6 +3569,13 @@ var __vue_render__$2 = function () {
3527
3569
  },
3528
3570
  }),
3529
3571
  _vm._v(" "),
3572
+ _vm._l(_vm.values.fields, function (field) {
3573
+ return _c("DynamicField", {
3574
+ key: field.name,
3575
+ attrs: { field: field },
3576
+ })
3577
+ }),
3578
+ _vm._v(" "),
3530
3579
  _c("form-field", {
3531
3580
  attrs: {
3532
3581
  name: "comment",
@@ -3543,7 +3592,7 @@ var __vue_render__$2 = function () {
3543
3592
  },
3544
3593
  }),
3545
3594
  ],
3546
- 1
3595
+ 2
3547
3596
  ),
3548
3597
  ]
3549
3598
  },
@@ -3575,7 +3624,7 @@ __vue_render__$2._withStripped = true;
3575
3624
  /* style */
3576
3625
  const __vue_inject_styles__$2 = function (inject) {
3577
3626
  if (!inject) return
3578
- inject("data-v-6400fd96_0", { source: ".date {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n column-gap: 10px;\n}\n.zone {\n display: flex;\n}\n.zone > *:first-child {\n flex: 1 1 1px;\n}\n.zone > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n}\n.link {\n display: flex;\n align-items: flex-end;\n}\n.link > *:first-child {\n flex: 1 1 1px;\n}\n.link > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n padding-bottom: 8px;\n}\n\n/*# sourceMappingURL=BannerForm.vue.map */", map: {"version":3,"sources":["/home/runner/work/tager-admin-banners/tager-admin-banners/src/views/Banners/BannerForm/BannerForm.vue","BannerForm.vue"],"names":[],"mappings":"AAiPA;EACA,aAAA;EACA,qCAAA;EACA,gBAAA;AChPA;ADmPA;EACA,aAAA;AChPA;ADkPA;EACA,aAAA;AChPA;ADmPA;EACA,eAAA;EACA,iBAAA;ACjPA;ADqPA;EACA,aAAA;EACA,qBAAA;AClPA;ADoPA;EACA,aAAA;AClPA;ADqPA;EACA,eAAA;EACA,iBAAA;EACA,mBAAA;ACnPA;;AAEA,yCAAyC","file":"BannerForm.vue","sourcesContent":["<template>\n <page\n :title=\"\n isCreation ? $t('banners:createBanner') : $t('banners:updateBanner')\n \"\n :is-content-loading=\"isContentLoading\"\n >\n <template v-slot:content>\n <form novalidate @submit.prevent=\"submitForm\">\n <div class=\"zone\">\n <form-field-select\n v-model=\"values.bannerZone\"\n name=\"bannerZone\"\n :label=\"$t('banners:zone')\"\n :options=\"zonesOptionList\"\n :error=\"errors.bannerZone\"\n />\n\n <form-field\n v-model=\"values.priority\"\n name=\"priority\"\n :label=\"$t('banners:priority')\"\n :error=\"errors.priority\"\n />\n </div>\n\n <input-label>{{ $t('banners:period') }}</input-label>\n\n <div class=\"date\">\n <form-field\n v-model=\"values.dateStart\"\n :label=\"$t('banners:from')\"\n name=\"dateStart\"\n type=\"date\"\n :max=\"values.dateEnd\"\n />\n\n <form-field\n v-model=\"values.dateEnd\"\n :label=\"$t('banners:to')\"\n name=\"dateEnd\"\n type=\"date\"\n :min=\"values.dateStart\"\n />\n </div>\n\n <form-field-checkbox\n v-model=\"values.disabled\"\n name=\"disabled\"\n :label=\"$t('banners:disabled')\"\n :error=\"errors.disabled\"\n />\n\n <div class=\"link\">\n <form-field\n v-model=\"values.link\"\n name=\"link\"\n :label=\"$t('banners:link')\"\n :error=\"errors.name\"\n />\n\n <form-field-checkbox\n v-model=\"values.openNewTab\"\n name=\"openNewTab\"\n :label=\"$t('banners:openNewTab')\"\n :error=\"errors.openNewTab\"\n />\n </div>\n\n <form-field-file-input\n v-model=\"values.image\"\n name=\"image\"\n file-type=\"image\"\n :label=\"$t('banners:image')\"\n :error=\"errors.file\"\n />\n\n <form-field\n v-model=\"values.comment\"\n name=\"comment\"\n type=\"textarea\"\n :label=\"$t('banners:comment')\"\n :error=\"errors.comment\"\n />\n </form>\n </template>\n\n <template v-slot:footer>\n <FormFooter\n :back-href=\"bannerListUrl\"\n :on-submit=\"submitForm\"\n :is-submitting=\"isSubmitting\"\n :is-creation=\"isCreation\"\n :can-create-another=\"isCreation\"\n />\n </template>\n </page>\n</template>\n\n<script lang=\"ts\">\nimport {\n computed,\n defineComponent,\n ref,\n SetupContext,\n watch,\n} from '@vue/composition-api';\n\nimport {FormFooter, OptionType, TagerFormSubmitEvent} from '@tager/admin-ui';\nimport {convertRequestErrorToMap} from '@tager/admin-services';\n\nimport {useFetchZones} from '../../../hooks';\nimport {BannerFormValues} from '../../../typings/banners';\nimport {useFetchBanner} from '../../../hooks/useFetchBanner';\nimport {\n getBannersBannerFormUrl,\n getBannersBannerListUrl,\n} from '../../../constants/paths';\nimport {createBanner, updateBanner} from '../../../services/requests';\n\nimport {\n convertBannerFormValuesToPayload,\n convertBannerToFormValues,\n} from './BannerForm.helpers';\n\nexport default defineComponent({\n name: 'BannerForm',\n components: {FormFooter},\n setup(props, context: SetupContext) {\n const bannerId = computed<string>(\n () => context.root.$route.params.bannerId\n );\n const isCreation = computed<boolean>(() => bannerId.value === 'create');\n\n /** Zones **/\n\n const {data: zones, loading: isZonesLoading} = useFetchZones({context});\n\n const zonesOptionList = computed<OptionType[]>(() =>\n zones.value.map<OptionType>((zone) => ({\n value: zone.id,\n label: zone.name,\n }))\n );\n\n /** Banner **/\n\n const {data: banner, loading: isBannerLoading} = useFetchBanner({\n context,\n bannerId,\n isCreation,\n });\n\n /** Form State **/\n\n const isSubmitting = ref<boolean>(false);\n const values = ref<BannerFormValues>(\n convertBannerToFormValues(banner.value, zonesOptionList.value)\n );\n const errors = ref<Record<string, string>>({});\n\n watch([banner, zones], () => {\n values.value = convertBannerToFormValues(\n banner.value,\n zonesOptionList.value\n );\n });\n\n const submitForm = (event: TagerFormSubmitEvent) => {\n isSubmitting.value = true;\n\n const body = convertBannerFormValuesToPayload(values.value);\n\n const requestPromise = isCreation.value\n ? createBanner(body)\n : updateBanner(bannerId.value, body);\n\n requestPromise\n .then(({data}) => {\n errors.value = {};\n\n if (event.type === 'create') {\n context.root.$router.push(\n getBannersBannerFormUrl({bannerId: String(data.id)})\n );\n }\n\n if (event.type === 'create_exit' || event.type === 'save_exit') {\n context.root.$router.push(getBannersBannerListUrl());\n }\n\n if (event.type === 'create_create-another') {\n values.value = convertBannerToFormValues(\n null,\n zonesOptionList.value\n );\n }\n\n context.root.$toast({\n variant: 'success',\n title: context.root.$t('banners:success'),\n body: isCreation.value\n ? context.root.$t('banners:bannerWasSuccessfullyCreated')\n : context.root.$t('banners:bannerWasSuccessfullyUpdated'),\n });\n })\n .catch((error) => {\n console.error(error);\n errors.value = convertRequestErrorToMap(error);\n context.root.$toast({\n variant: 'danger',\n title: context.root.$t('banners:error'),\n body: isCreation.value\n ? context.root.$t('banners:bannerCreationWasFailed')\n : context.root.$t('banners:bannerUpdateWasFailed'),\n });\n })\n .finally(() => {\n isSubmitting.value = false;\n });\n };\n\n const isContentLoading = computed<boolean>(\n () => isBannerLoading.value || isZonesLoading.value\n );\n\n return {\n isCreation,\n isContentLoading,\n isSubmitting,\n values,\n errors,\n submitForm,\n bannerListUrl: getBannersBannerListUrl(),\n zonesOptionList,\n };\n },\n});\n</script>\n\n<style lang=\"scss\">\n.date {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n column-gap: 10px;\n}\n\n.zone {\n display: flex;\n\n > *:first-child {\n flex: 1 1 1px;\n }\n\n > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n }\n}\n\n.link {\n display: flex;\n align-items: flex-end;\n\n > *:first-child {\n flex: 1 1 1px;\n }\n\n > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n padding-bottom: 8px;\n }\n}\n</style>\n",".date {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n column-gap: 10px;\n}\n\n.zone {\n display: flex;\n}\n.zone > *:first-child {\n flex: 1 1 1px;\n}\n.zone > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n}\n\n.link {\n display: flex;\n align-items: flex-end;\n}\n.link > *:first-child {\n flex: 1 1 1px;\n}\n.link > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n padding-bottom: 8px;\n}\n\n/*# sourceMappingURL=BannerForm.vue.map */"]}, media: undefined });
3627
+ inject("data-v-ddc2a1b6_0", { source: ".date {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n column-gap: 10px;\n}\n.zone {\n display: flex;\n}\n.zone > *:first-child {\n flex: 1 1 1px;\n}\n.zone > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n}\n.link {\n display: flex;\n align-items: flex-end;\n}\n.link > *:first-child {\n flex: 1 1 1px;\n}\n.link > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n padding-bottom: 8px;\n}\n\n/*# sourceMappingURL=BannerForm.vue.map */", map: {"version":3,"sources":["/home/runner/work/tager-admin-banners/tager-admin-banners/src/views/Banners/BannerForm/BannerForm.vue","BannerForm.vue"],"names":[],"mappings":"AA8QA;EACA,aAAA;EACA,qCAAA;EACA,gBAAA;AC7QA;ADgRA;EACA,aAAA;AC7QA;AD+QA;EACA,aAAA;AC7QA;ADgRA;EACA,eAAA;EACA,iBAAA;AC9QA;ADkRA;EACA,aAAA;EACA,qBAAA;AC/QA;ADiRA;EACA,aAAA;AC/QA;ADkRA;EACA,eAAA;EACA,iBAAA;EACA,mBAAA;AChRA;;AAEA,yCAAyC","file":"BannerForm.vue","sourcesContent":["<template>\n <page\n :title=\"\n isCreation ? $t('banners:createBanner') : $t('banners:updateBanner')\n \"\n :is-content-loading=\"isContentLoading\"\n >\n <template v-slot:content>\n <form novalidate @submit.prevent=\"submitForm\">\n <div class=\"zone\">\n <form-field-select\n v-model=\"values.bannerZone\"\n name=\"bannerZone\"\n :label=\"$t('banners:zone')\"\n :options=\"zonesOptionList\"\n :error=\"errors.bannerZone\"\n />\n\n <form-field\n v-model=\"values.priority\"\n name=\"priority\"\n :label=\"$t('banners:priority')\"\n :error=\"errors.priority\"\n />\n </div>\n\n <input-label>{{ $t('banners:period') }}</input-label>\n\n <div class=\"date\">\n <form-field\n v-model=\"values.dateStart\"\n :label=\"$t('banners:from')\"\n name=\"dateStart\"\n type=\"date\"\n :max=\"values.dateEnd\"\n />\n\n <form-field\n v-model=\"values.dateEnd\"\n :label=\"$t('banners:to')\"\n name=\"dateEnd\"\n type=\"date\"\n :min=\"values.dateStart\"\n />\n </div>\n\n <form-field-checkbox\n v-model=\"values.disabled\"\n name=\"disabled\"\n :label=\"$t('banners:disabled')\"\n :error=\"errors.disabled\"\n />\n\n <div class=\"link\">\n <form-field\n v-model=\"values.link\"\n name=\"link\"\n :label=\"$t('banners:link')\"\n :error=\"errors.name\"\n />\n\n <form-field-checkbox\n v-model=\"values.openNewTab\"\n name=\"openNewTab\"\n :label=\"$t('banners:openNewTab')\"\n :error=\"errors.openNewTab\"\n />\n </div>\n\n <form-field-file-input\n v-model=\"values.image\"\n name=\"image\"\n file-type=\"image\"\n :label=\"$t('banners:image')\"\n :error=\"errors.file\"\n />\n\n <DynamicField\n v-for=\"field of values.fields\"\n :key=\"field.name\"\n :field=\"field\"\n />\n\n <form-field\n v-model=\"values.comment\"\n name=\"comment\"\n type=\"textarea\"\n :label=\"$t('banners:comment')\"\n :error=\"errors.comment\"\n />\n </form>\n </template>\n\n <template v-slot:footer>\n <FormFooter\n :back-href=\"bannerListUrl\"\n :on-submit=\"submitForm\"\n :is-submitting=\"isSubmitting\"\n :is-creation=\"isCreation\"\n :can-create-another=\"isCreation\"\n />\n </template>\n </page>\n</template>\n\n<script lang=\"ts\">\nimport {\n computed,\n defineComponent,\n ref,\n SetupContext,\n watch,\n} from '@vue/composition-api';\n\nimport { FormFooter, OptionType, TagerFormSubmitEvent } from '@tager/admin-ui';\nimport { DynamicField, universalFieldUtils } from '@tager/admin-dynamic-field';\nimport { convertRequestErrorToMap } from '@tager/admin-services';\n\nimport { useFetchZones } from '../../../hooks';\nimport { BannerFormValues } from '../../../typings/banners';\nimport { useFetchBanner } from '../../../hooks/useFetchBanner';\nimport {\n getBannersBannerFormUrl,\n getBannersBannerListUrl,\n} from '../../../constants/paths';\nimport { createBanner, updateBanner } from '../../../services/requests';\nimport { useFetchZoneFields } from '../../../hooks/useFetchZoneFields';\n\nimport {\n convertBannerFormValuesToPayload,\n convertBannerToFormValues,\n} from './BannerForm.helpers';\n\nexport default defineComponent({\n name: 'BannerForm',\n components: { FormFooter, DynamicField },\n setup(props, context: SetupContext) {\n const bannerId = computed<string>(\n () => context.root.$route.params.bannerId\n );\n const isCreation = computed<boolean>(() => bannerId.value === 'create');\n\n /** Zones **/\n\n const { data: zones, loading: isZonesLoading } = useFetchZones({ context });\n\n const zonesOptionList = computed<OptionType[]>(() =>\n zones.value.map<OptionType>((zone) => ({\n value: zone.id,\n label: zone.name,\n }))\n );\n\n /** Banner **/\n\n const { data: banner, loading: isBannerLoading } = useFetchBanner({\n context,\n bannerId,\n isCreation,\n });\n\n /** Form State **/\n\n const isSubmitting = ref<boolean>(false);\n const values = ref<BannerFormValues>(\n convertBannerToFormValues(banner.value, zonesOptionList.value)\n );\n const errors = ref<Record<string, string>>({});\n\n watch([banner, zones], () => {\n values.value = convertBannerToFormValues(\n banner.value,\n zonesOptionList.value\n );\n });\n\n /** Zone Fields **/\n\n const {\n loading: isZoneFieldsLoading,\n data: zoneFields,\n } = useFetchZoneFields({ context, values });\n\n watch(zoneFields, () => {\n values.value.fields = (\n zoneFields.value?.fields ?? []\n ).map((fieldConfig, index) =>\n universalFieldUtils.createFormField(\n fieldConfig,\n banner.value ? banner.value.fields[index].value ?? null : null\n )\n );\n });\n\n const submitForm = (event: TagerFormSubmitEvent) => {\n isSubmitting.value = true;\n\n const body = convertBannerFormValuesToPayload(values.value);\n\n const requestPromise = isCreation.value\n ? createBanner(body)\n : updateBanner(bannerId.value, body);\n\n requestPromise\n .then(({ data }) => {\n errors.value = {};\n\n if (event.type === 'create') {\n context.root.$router.push(\n getBannersBannerFormUrl({ bannerId: String(data.id) })\n );\n }\n\n if (event.type === 'create_exit' || event.type === 'save_exit') {\n context.root.$router.push(getBannersBannerListUrl());\n }\n\n if (event.type === 'create_create-another') {\n values.value = convertBannerToFormValues(\n null,\n zonesOptionList.value\n );\n }\n\n context.root.$toast({\n variant: 'success',\n title: context.root.$t('banners:success'),\n body: isCreation.value\n ? context.root.$t('banners:bannerWasSuccessfullyCreated')\n : context.root.$t('banners:bannerWasSuccessfullyUpdated'),\n });\n })\n .catch((error) => {\n console.error(error);\n errors.value = convertRequestErrorToMap(error);\n context.root.$toast({\n variant: 'danger',\n title: context.root.$t('banners:error'),\n body: isCreation.value\n ? context.root.$t('banners:bannerCreationWasFailed')\n : context.root.$t('banners:bannerUpdateWasFailed'),\n });\n })\n .finally(() => {\n isSubmitting.value = false;\n });\n };\n\n const isContentLoading = computed<boolean>(\n () =>\n isBannerLoading.value ||\n isZonesLoading.value ||\n isZoneFieldsLoading.value\n );\n\n return {\n isCreation,\n isContentLoading,\n isSubmitting,\n values,\n errors,\n submitForm,\n bannerListUrl: getBannersBannerListUrl(),\n zonesOptionList,\n };\n },\n});\n</script>\n\n<style lang=\"scss\">\n.date {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n column-gap: 10px;\n}\n\n.zone {\n display: flex;\n\n > *:first-child {\n flex: 1 1 1px;\n }\n\n > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n }\n}\n\n.link {\n display: flex;\n align-items: flex-end;\n\n > *:first-child {\n flex: 1 1 1px;\n }\n\n > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n padding-bottom: 8px;\n }\n}\n</style>\n",".date {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n column-gap: 10px;\n}\n\n.zone {\n display: flex;\n}\n.zone > *:first-child {\n flex: 1 1 1px;\n}\n.zone > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n}\n\n.link {\n display: flex;\n align-items: flex-end;\n}\n.link > *:first-child {\n flex: 1 1 1px;\n}\n.link > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n padding-bottom: 8px;\n}\n\n/*# sourceMappingURL=BannerForm.vue.map */"]}, media: undefined });
3579
3628
 
3580
3629
  };
3581
3630
  /* scoped */
@@ -3657,4 +3706,4 @@ function getBannersMenuItem(params) {
3657
3706
  i18n.addTranslations('en', 'banners', EN);
3658
3707
  i18n.addTranslations('ru', 'banners', RU);
3659
3708
 
3660
- export { BANNERS_BANNER_FORM_ROUTE, BANNERS_BANNER_LIST_ROUTE, BANNERS_ROUTE_PATHS, BANNERS_ZONE_LIST_ROUTE, createBanner, deleteBanner, getBanner, getBannerCount, getBanners, getBannersBannerFormUrl, getBannersBannerListUrl, getBannersMenuItem, getBannersZoneListUrl, getZones, updateBanner };
3709
+ export { BANNERS_BANNER_FORM_ROUTE, BANNERS_BANNER_LIST_ROUTE, BANNERS_ROUTE_PATHS, BANNERS_ZONE_LIST_ROUTE, createBanner, deleteBanner, getBanner, getBannerCount, getBanners, getBannersBannerFormUrl, getBannersBannerListUrl, getBannersMenuItem, getBannersZoneListUrl, getZoneFields, getZones, updateBanner };
package/dist/index.umd.js CHANGED
@@ -1,8 +1,8 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@tager/admin-services'), require('@vue/composition-api'), require('@tager/admin-ui'), require('path-to-regexp')) :
3
- typeof define === 'function' && define.amd ? define(['exports', '@tager/admin-services', '@vue/composition-api', '@tager/admin-ui', 'path-to-regexp'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.TagerAdminBanners = {}, global.adminServices, global.compositionApi, global.adminUi, global.pathToRegexp));
5
- }(this, (function (exports, adminServices, compositionApi, adminUi, pathToRegexp) { 'use strict';
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@tager/admin-services'), require('@vue/composition-api'), require('@tager/admin-ui'), require('path-to-regexp'), require('@tager/admin-dynamic-field')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', '@tager/admin-services', '@vue/composition-api', '@tager/admin-ui', 'path-to-regexp', '@tager/admin-dynamic-field'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.TagerAdminBanners = {}, global.adminServices, global.compositionApi, global.adminUi, global.pathToRegexp, global.adminDynamicField));
5
+ }(this, (function (exports, adminServices, compositionApi, adminUi, pathToRegexp, adminDynamicField) { 'use strict';
6
6
 
7
7
  const EN = {
8
8
  home: 'Home',
@@ -90,6 +90,9 @@
90
90
  function getZones(params) {
91
91
  return adminServices.request.get({ path: '/admin/adv/zones', params });
92
92
  }
93
+ function getZoneFields(zoneId) {
94
+ return adminServices.request.get({ path: `/admin/adv/zones/${zoneId}` });
95
+ }
93
96
  /** Banners **/
94
97
  function getBanners(params) {
95
98
  return adminServices.request.get({ path: '/admin/adv', params });
@@ -3249,11 +3252,34 @@
3249
3252
  return resource;
3250
3253
  }
3251
3254
 
3255
+ function useFetchZoneFields({ context, values, }) {
3256
+ const zoneId = compositionApi.computed(() => { var _a, _b; return (_b = (_a = values.value.bannerZone) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : ''; });
3257
+ const [fetchZoneFields, resource] = adminServices.useResource({
3258
+ fetchResource: () => getZoneFields(zoneId.value),
3259
+ initialValue: null,
3260
+ context,
3261
+ resourceName: 'Zone Fields',
3262
+ });
3263
+ compositionApi.onMounted(() => {
3264
+ if (!zoneId.value) {
3265
+ return;
3266
+ }
3267
+ fetchZoneFields();
3268
+ });
3269
+ compositionApi.watch(zoneId, () => {
3270
+ if (!zoneId.value) {
3271
+ return;
3272
+ }
3273
+ fetchZoneFields();
3274
+ });
3275
+ return resource;
3276
+ }
3277
+
3252
3278
  function convertBannerToFormValues(banner, zonesOptionList) {
3253
3279
  var _a, _b, _c, _d, _e, _f, _g;
3254
3280
  const foundZone = zonesOptionList.find(({ value }) => value === (banner === null || banner === void 0 ? void 0 : banner.bannerZone));
3255
3281
  return {
3256
- priority: (_a = banner === null || banner === void 0 ? void 0 : banner.priority) !== null && _a !== void 0 ? _a : 1,
3282
+ priority: String((_a = banner === null || banner === void 0 ? void 0 : banner.priority) !== null && _a !== void 0 ? _a : 1),
3257
3283
  link: (_b = banner === null || banner === void 0 ? void 0 : banner.link) !== null && _b !== void 0 ? _b : '',
3258
3284
  image: (banner === null || banner === void 0 ? void 0 : banner.image) ? { id: adminServices.createId(), file: banner.image } : null,
3259
3285
  bannerZone: foundZone !== null && foundZone !== void 0 ? foundZone : null,
@@ -3262,16 +3288,20 @@
3262
3288
  dateEnd: (_e = banner === null || banner === void 0 ? void 0 : banner.dateEnd) !== null && _e !== void 0 ? _e : '',
3263
3289
  disabled: (_f = banner === null || banner === void 0 ? void 0 : banner.disabled) !== null && _f !== void 0 ? _f : false,
3264
3290
  comment: (_g = banner === null || banner === void 0 ? void 0 : banner.comment) !== null && _g !== void 0 ? _g : '',
3291
+ fields: [],
3265
3292
  };
3266
3293
  }
3267
3294
  function convertBannerFormValuesToPayload(values) {
3268
3295
  var _a, _b, _c, _d;
3269
- return Object.assign(Object.assign({}, values), { priority: values.priority ? Number(values.priority) : 1, dateStart: values.dateStart ? values.dateStart : null, dateEnd: values.dateEnd ? values.dateEnd : null, image: (_b = (_a = values.image) === null || _a === void 0 ? void 0 : _a.file.id) !== null && _b !== void 0 ? _b : null, bannerZone: (_d = (_c = values.bannerZone) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : '' });
3296
+ return Object.assign(Object.assign({}, values), { priority: values.priority ? Number(values.priority) : 1, dateStart: values.dateStart ? values.dateStart : null, dateEnd: values.dateEnd ? values.dateEnd : null, image: (_b = (_a = values.image) === null || _a === void 0 ? void 0 : _a.file.id) !== null && _b !== void 0 ? _b : null, bannerZone: (_d = (_c = values.bannerZone) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : '', fields: values.fields.map((field) => ({
3297
+ name: field.config.name,
3298
+ value: adminDynamicField.universalFieldUtils.getOutgoingValue(field),
3299
+ })) });
3270
3300
  }
3271
3301
 
3272
3302
  var script$2 = compositionApi.defineComponent({
3273
3303
  name: 'BannerForm',
3274
- components: { FormFooter: adminUi.FormFooter },
3304
+ components: { FormFooter: adminUi.FormFooter, DynamicField: adminDynamicField.DynamicField },
3275
3305
  setup(props, context) {
3276
3306
  const bannerId = compositionApi.computed(() => context.root.$route.params.bannerId);
3277
3307
  const isCreation = compositionApi.computed(() => bannerId.value === 'create');
@@ -3294,6 +3324,15 @@
3294
3324
  compositionApi.watch([banner, zones], () => {
3295
3325
  values.value = convertBannerToFormValues(banner.value, zonesOptionList.value);
3296
3326
  });
3327
+ /** Zone Fields **/
3328
+ const { loading: isZoneFieldsLoading, data: zoneFields, } = useFetchZoneFields({ context, values });
3329
+ compositionApi.watch(zoneFields, () => {
3330
+ var _a, _b;
3331
+ values.value.fields = ((_b = (_a = zoneFields.value) === null || _a === void 0 ? void 0 : _a.fields) !== null && _b !== void 0 ? _b : []).map((fieldConfig, index) => {
3332
+ var _a;
3333
+ return adminDynamicField.universalFieldUtils.createFormField(fieldConfig, banner.value ? (_a = banner.value.fields[index].value) !== null && _a !== void 0 ? _a : null : null);
3334
+ });
3335
+ });
3297
3336
  const submitForm = (event) => {
3298
3337
  isSubmitting.value = true;
3299
3338
  const body = convertBannerFormValuesToPayload(values.value);
@@ -3335,7 +3374,9 @@
3335
3374
  isSubmitting.value = false;
3336
3375
  });
3337
3376
  };
3338
- const isContentLoading = compositionApi.computed(() => isBannerLoading.value || isZonesLoading.value);
3377
+ const isContentLoading = compositionApi.computed(() => isBannerLoading.value ||
3378
+ isZonesLoading.value ||
3379
+ isZoneFieldsLoading.value);
3339
3380
  return {
3340
3381
  isCreation,
3341
3382
  isContentLoading,
@@ -3528,6 +3569,13 @@
3528
3569
  },
3529
3570
  }),
3530
3571
  _vm._v(" "),
3572
+ _vm._l(_vm.values.fields, function (field) {
3573
+ return _c("DynamicField", {
3574
+ key: field.name,
3575
+ attrs: { field: field },
3576
+ })
3577
+ }),
3578
+ _vm._v(" "),
3531
3579
  _c("form-field", {
3532
3580
  attrs: {
3533
3581
  name: "comment",
@@ -3544,7 +3592,7 @@
3544
3592
  },
3545
3593
  }),
3546
3594
  ],
3547
- 1
3595
+ 2
3548
3596
  ),
3549
3597
  ]
3550
3598
  },
@@ -3576,7 +3624,7 @@
3576
3624
  /* style */
3577
3625
  const __vue_inject_styles__$2 = function (inject) {
3578
3626
  if (!inject) return
3579
- inject("data-v-6400fd96_0", { source: ".date {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n column-gap: 10px;\n}\n.zone {\n display: flex;\n}\n.zone > *:first-child {\n flex: 1 1 1px;\n}\n.zone > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n}\n.link {\n display: flex;\n align-items: flex-end;\n}\n.link > *:first-child {\n flex: 1 1 1px;\n}\n.link > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n padding-bottom: 8px;\n}\n\n/*# sourceMappingURL=BannerForm.vue.map */", map: {"version":3,"sources":["/home/runner/work/tager-admin-banners/tager-admin-banners/src/views/Banners/BannerForm/BannerForm.vue","BannerForm.vue"],"names":[],"mappings":"AAiPA;EACA,aAAA;EACA,qCAAA;EACA,gBAAA;AChPA;ADmPA;EACA,aAAA;AChPA;ADkPA;EACA,aAAA;AChPA;ADmPA;EACA,eAAA;EACA,iBAAA;ACjPA;ADqPA;EACA,aAAA;EACA,qBAAA;AClPA;ADoPA;EACA,aAAA;AClPA;ADqPA;EACA,eAAA;EACA,iBAAA;EACA,mBAAA;ACnPA;;AAEA,yCAAyC","file":"BannerForm.vue","sourcesContent":["<template>\n <page\n :title=\"\n isCreation ? $t('banners:createBanner') : $t('banners:updateBanner')\n \"\n :is-content-loading=\"isContentLoading\"\n >\n <template v-slot:content>\n <form novalidate @submit.prevent=\"submitForm\">\n <div class=\"zone\">\n <form-field-select\n v-model=\"values.bannerZone\"\n name=\"bannerZone\"\n :label=\"$t('banners:zone')\"\n :options=\"zonesOptionList\"\n :error=\"errors.bannerZone\"\n />\n\n <form-field\n v-model=\"values.priority\"\n name=\"priority\"\n :label=\"$t('banners:priority')\"\n :error=\"errors.priority\"\n />\n </div>\n\n <input-label>{{ $t('banners:period') }}</input-label>\n\n <div class=\"date\">\n <form-field\n v-model=\"values.dateStart\"\n :label=\"$t('banners:from')\"\n name=\"dateStart\"\n type=\"date\"\n :max=\"values.dateEnd\"\n />\n\n <form-field\n v-model=\"values.dateEnd\"\n :label=\"$t('banners:to')\"\n name=\"dateEnd\"\n type=\"date\"\n :min=\"values.dateStart\"\n />\n </div>\n\n <form-field-checkbox\n v-model=\"values.disabled\"\n name=\"disabled\"\n :label=\"$t('banners:disabled')\"\n :error=\"errors.disabled\"\n />\n\n <div class=\"link\">\n <form-field\n v-model=\"values.link\"\n name=\"link\"\n :label=\"$t('banners:link')\"\n :error=\"errors.name\"\n />\n\n <form-field-checkbox\n v-model=\"values.openNewTab\"\n name=\"openNewTab\"\n :label=\"$t('banners:openNewTab')\"\n :error=\"errors.openNewTab\"\n />\n </div>\n\n <form-field-file-input\n v-model=\"values.image\"\n name=\"image\"\n file-type=\"image\"\n :label=\"$t('banners:image')\"\n :error=\"errors.file\"\n />\n\n <form-field\n v-model=\"values.comment\"\n name=\"comment\"\n type=\"textarea\"\n :label=\"$t('banners:comment')\"\n :error=\"errors.comment\"\n />\n </form>\n </template>\n\n <template v-slot:footer>\n <FormFooter\n :back-href=\"bannerListUrl\"\n :on-submit=\"submitForm\"\n :is-submitting=\"isSubmitting\"\n :is-creation=\"isCreation\"\n :can-create-another=\"isCreation\"\n />\n </template>\n </page>\n</template>\n\n<script lang=\"ts\">\nimport {\n computed,\n defineComponent,\n ref,\n SetupContext,\n watch,\n} from '@vue/composition-api';\n\nimport {FormFooter, OptionType, TagerFormSubmitEvent} from '@tager/admin-ui';\nimport {convertRequestErrorToMap} from '@tager/admin-services';\n\nimport {useFetchZones} from '../../../hooks';\nimport {BannerFormValues} from '../../../typings/banners';\nimport {useFetchBanner} from '../../../hooks/useFetchBanner';\nimport {\n getBannersBannerFormUrl,\n getBannersBannerListUrl,\n} from '../../../constants/paths';\nimport {createBanner, updateBanner} from '../../../services/requests';\n\nimport {\n convertBannerFormValuesToPayload,\n convertBannerToFormValues,\n} from './BannerForm.helpers';\n\nexport default defineComponent({\n name: 'BannerForm',\n components: {FormFooter},\n setup(props, context: SetupContext) {\n const bannerId = computed<string>(\n () => context.root.$route.params.bannerId\n );\n const isCreation = computed<boolean>(() => bannerId.value === 'create');\n\n /** Zones **/\n\n const {data: zones, loading: isZonesLoading} = useFetchZones({context});\n\n const zonesOptionList = computed<OptionType[]>(() =>\n zones.value.map<OptionType>((zone) => ({\n value: zone.id,\n label: zone.name,\n }))\n );\n\n /** Banner **/\n\n const {data: banner, loading: isBannerLoading} = useFetchBanner({\n context,\n bannerId,\n isCreation,\n });\n\n /** Form State **/\n\n const isSubmitting = ref<boolean>(false);\n const values = ref<BannerFormValues>(\n convertBannerToFormValues(banner.value, zonesOptionList.value)\n );\n const errors = ref<Record<string, string>>({});\n\n watch([banner, zones], () => {\n values.value = convertBannerToFormValues(\n banner.value,\n zonesOptionList.value\n );\n });\n\n const submitForm = (event: TagerFormSubmitEvent) => {\n isSubmitting.value = true;\n\n const body = convertBannerFormValuesToPayload(values.value);\n\n const requestPromise = isCreation.value\n ? createBanner(body)\n : updateBanner(bannerId.value, body);\n\n requestPromise\n .then(({data}) => {\n errors.value = {};\n\n if (event.type === 'create') {\n context.root.$router.push(\n getBannersBannerFormUrl({bannerId: String(data.id)})\n );\n }\n\n if (event.type === 'create_exit' || event.type === 'save_exit') {\n context.root.$router.push(getBannersBannerListUrl());\n }\n\n if (event.type === 'create_create-another') {\n values.value = convertBannerToFormValues(\n null,\n zonesOptionList.value\n );\n }\n\n context.root.$toast({\n variant: 'success',\n title: context.root.$t('banners:success'),\n body: isCreation.value\n ? context.root.$t('banners:bannerWasSuccessfullyCreated')\n : context.root.$t('banners:bannerWasSuccessfullyUpdated'),\n });\n })\n .catch((error) => {\n console.error(error);\n errors.value = convertRequestErrorToMap(error);\n context.root.$toast({\n variant: 'danger',\n title: context.root.$t('banners:error'),\n body: isCreation.value\n ? context.root.$t('banners:bannerCreationWasFailed')\n : context.root.$t('banners:bannerUpdateWasFailed'),\n });\n })\n .finally(() => {\n isSubmitting.value = false;\n });\n };\n\n const isContentLoading = computed<boolean>(\n () => isBannerLoading.value || isZonesLoading.value\n );\n\n return {\n isCreation,\n isContentLoading,\n isSubmitting,\n values,\n errors,\n submitForm,\n bannerListUrl: getBannersBannerListUrl(),\n zonesOptionList,\n };\n },\n});\n</script>\n\n<style lang=\"scss\">\n.date {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n column-gap: 10px;\n}\n\n.zone {\n display: flex;\n\n > *:first-child {\n flex: 1 1 1px;\n }\n\n > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n }\n}\n\n.link {\n display: flex;\n align-items: flex-end;\n\n > *:first-child {\n flex: 1 1 1px;\n }\n\n > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n padding-bottom: 8px;\n }\n}\n</style>\n",".date {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n column-gap: 10px;\n}\n\n.zone {\n display: flex;\n}\n.zone > *:first-child {\n flex: 1 1 1px;\n}\n.zone > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n}\n\n.link {\n display: flex;\n align-items: flex-end;\n}\n.link > *:first-child {\n flex: 1 1 1px;\n}\n.link > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n padding-bottom: 8px;\n}\n\n/*# sourceMappingURL=BannerForm.vue.map */"]}, media: undefined });
3627
+ inject("data-v-ddc2a1b6_0", { source: ".date {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n column-gap: 10px;\n}\n.zone {\n display: flex;\n}\n.zone > *:first-child {\n flex: 1 1 1px;\n}\n.zone > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n}\n.link {\n display: flex;\n align-items: flex-end;\n}\n.link > *:first-child {\n flex: 1 1 1px;\n}\n.link > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n padding-bottom: 8px;\n}\n\n/*# sourceMappingURL=BannerForm.vue.map */", map: {"version":3,"sources":["/home/runner/work/tager-admin-banners/tager-admin-banners/src/views/Banners/BannerForm/BannerForm.vue","BannerForm.vue"],"names":[],"mappings":"AA8QA;EACA,aAAA;EACA,qCAAA;EACA,gBAAA;AC7QA;ADgRA;EACA,aAAA;AC7QA;AD+QA;EACA,aAAA;AC7QA;ADgRA;EACA,eAAA;EACA,iBAAA;AC9QA;ADkRA;EACA,aAAA;EACA,qBAAA;AC/QA;ADiRA;EACA,aAAA;AC/QA;ADkRA;EACA,eAAA;EACA,iBAAA;EACA,mBAAA;AChRA;;AAEA,yCAAyC","file":"BannerForm.vue","sourcesContent":["<template>\n <page\n :title=\"\n isCreation ? $t('banners:createBanner') : $t('banners:updateBanner')\n \"\n :is-content-loading=\"isContentLoading\"\n >\n <template v-slot:content>\n <form novalidate @submit.prevent=\"submitForm\">\n <div class=\"zone\">\n <form-field-select\n v-model=\"values.bannerZone\"\n name=\"bannerZone\"\n :label=\"$t('banners:zone')\"\n :options=\"zonesOptionList\"\n :error=\"errors.bannerZone\"\n />\n\n <form-field\n v-model=\"values.priority\"\n name=\"priority\"\n :label=\"$t('banners:priority')\"\n :error=\"errors.priority\"\n />\n </div>\n\n <input-label>{{ $t('banners:period') }}</input-label>\n\n <div class=\"date\">\n <form-field\n v-model=\"values.dateStart\"\n :label=\"$t('banners:from')\"\n name=\"dateStart\"\n type=\"date\"\n :max=\"values.dateEnd\"\n />\n\n <form-field\n v-model=\"values.dateEnd\"\n :label=\"$t('banners:to')\"\n name=\"dateEnd\"\n type=\"date\"\n :min=\"values.dateStart\"\n />\n </div>\n\n <form-field-checkbox\n v-model=\"values.disabled\"\n name=\"disabled\"\n :label=\"$t('banners:disabled')\"\n :error=\"errors.disabled\"\n />\n\n <div class=\"link\">\n <form-field\n v-model=\"values.link\"\n name=\"link\"\n :label=\"$t('banners:link')\"\n :error=\"errors.name\"\n />\n\n <form-field-checkbox\n v-model=\"values.openNewTab\"\n name=\"openNewTab\"\n :label=\"$t('banners:openNewTab')\"\n :error=\"errors.openNewTab\"\n />\n </div>\n\n <form-field-file-input\n v-model=\"values.image\"\n name=\"image\"\n file-type=\"image\"\n :label=\"$t('banners:image')\"\n :error=\"errors.file\"\n />\n\n <DynamicField\n v-for=\"field of values.fields\"\n :key=\"field.name\"\n :field=\"field\"\n />\n\n <form-field\n v-model=\"values.comment\"\n name=\"comment\"\n type=\"textarea\"\n :label=\"$t('banners:comment')\"\n :error=\"errors.comment\"\n />\n </form>\n </template>\n\n <template v-slot:footer>\n <FormFooter\n :back-href=\"bannerListUrl\"\n :on-submit=\"submitForm\"\n :is-submitting=\"isSubmitting\"\n :is-creation=\"isCreation\"\n :can-create-another=\"isCreation\"\n />\n </template>\n </page>\n</template>\n\n<script lang=\"ts\">\nimport {\n computed,\n defineComponent,\n ref,\n SetupContext,\n watch,\n} from '@vue/composition-api';\n\nimport { FormFooter, OptionType, TagerFormSubmitEvent } from '@tager/admin-ui';\nimport { DynamicField, universalFieldUtils } from '@tager/admin-dynamic-field';\nimport { convertRequestErrorToMap } from '@tager/admin-services';\n\nimport { useFetchZones } from '../../../hooks';\nimport { BannerFormValues } from '../../../typings/banners';\nimport { useFetchBanner } from '../../../hooks/useFetchBanner';\nimport {\n getBannersBannerFormUrl,\n getBannersBannerListUrl,\n} from '../../../constants/paths';\nimport { createBanner, updateBanner } from '../../../services/requests';\nimport { useFetchZoneFields } from '../../../hooks/useFetchZoneFields';\n\nimport {\n convertBannerFormValuesToPayload,\n convertBannerToFormValues,\n} from './BannerForm.helpers';\n\nexport default defineComponent({\n name: 'BannerForm',\n components: { FormFooter, DynamicField },\n setup(props, context: SetupContext) {\n const bannerId = computed<string>(\n () => context.root.$route.params.bannerId\n );\n const isCreation = computed<boolean>(() => bannerId.value === 'create');\n\n /** Zones **/\n\n const { data: zones, loading: isZonesLoading } = useFetchZones({ context });\n\n const zonesOptionList = computed<OptionType[]>(() =>\n zones.value.map<OptionType>((zone) => ({\n value: zone.id,\n label: zone.name,\n }))\n );\n\n /** Banner **/\n\n const { data: banner, loading: isBannerLoading } = useFetchBanner({\n context,\n bannerId,\n isCreation,\n });\n\n /** Form State **/\n\n const isSubmitting = ref<boolean>(false);\n const values = ref<BannerFormValues>(\n convertBannerToFormValues(banner.value, zonesOptionList.value)\n );\n const errors = ref<Record<string, string>>({});\n\n watch([banner, zones], () => {\n values.value = convertBannerToFormValues(\n banner.value,\n zonesOptionList.value\n );\n });\n\n /** Zone Fields **/\n\n const {\n loading: isZoneFieldsLoading,\n data: zoneFields,\n } = useFetchZoneFields({ context, values });\n\n watch(zoneFields, () => {\n values.value.fields = (\n zoneFields.value?.fields ?? []\n ).map((fieldConfig, index) =>\n universalFieldUtils.createFormField(\n fieldConfig,\n banner.value ? banner.value.fields[index].value ?? null : null\n )\n );\n });\n\n const submitForm = (event: TagerFormSubmitEvent) => {\n isSubmitting.value = true;\n\n const body = convertBannerFormValuesToPayload(values.value);\n\n const requestPromise = isCreation.value\n ? createBanner(body)\n : updateBanner(bannerId.value, body);\n\n requestPromise\n .then(({ data }) => {\n errors.value = {};\n\n if (event.type === 'create') {\n context.root.$router.push(\n getBannersBannerFormUrl({ bannerId: String(data.id) })\n );\n }\n\n if (event.type === 'create_exit' || event.type === 'save_exit') {\n context.root.$router.push(getBannersBannerListUrl());\n }\n\n if (event.type === 'create_create-another') {\n values.value = convertBannerToFormValues(\n null,\n zonesOptionList.value\n );\n }\n\n context.root.$toast({\n variant: 'success',\n title: context.root.$t('banners:success'),\n body: isCreation.value\n ? context.root.$t('banners:bannerWasSuccessfullyCreated')\n : context.root.$t('banners:bannerWasSuccessfullyUpdated'),\n });\n })\n .catch((error) => {\n console.error(error);\n errors.value = convertRequestErrorToMap(error);\n context.root.$toast({\n variant: 'danger',\n title: context.root.$t('banners:error'),\n body: isCreation.value\n ? context.root.$t('banners:bannerCreationWasFailed')\n : context.root.$t('banners:bannerUpdateWasFailed'),\n });\n })\n .finally(() => {\n isSubmitting.value = false;\n });\n };\n\n const isContentLoading = computed<boolean>(\n () =>\n isBannerLoading.value ||\n isZonesLoading.value ||\n isZoneFieldsLoading.value\n );\n\n return {\n isCreation,\n isContentLoading,\n isSubmitting,\n values,\n errors,\n submitForm,\n bannerListUrl: getBannersBannerListUrl(),\n zonesOptionList,\n };\n },\n});\n</script>\n\n<style lang=\"scss\">\n.date {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n column-gap: 10px;\n}\n\n.zone {\n display: flex;\n\n > *:first-child {\n flex: 1 1 1px;\n }\n\n > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n }\n}\n\n.link {\n display: flex;\n align-items: flex-end;\n\n > *:first-child {\n flex: 1 1 1px;\n }\n\n > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n padding-bottom: 8px;\n }\n}\n</style>\n",".date {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n column-gap: 10px;\n}\n\n.zone {\n display: flex;\n}\n.zone > *:first-child {\n flex: 1 1 1px;\n}\n.zone > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n}\n\n.link {\n display: flex;\n align-items: flex-end;\n}\n.link > *:first-child {\n flex: 1 1 1px;\n}\n.link > *:last-child {\n flex-basis: 30%;\n margin-left: 20px;\n padding-bottom: 8px;\n}\n\n/*# sourceMappingURL=BannerForm.vue.map */"]}, media: undefined });
3580
3628
 
3581
3629
  };
3582
3630
  /* scoped */
@@ -3671,6 +3719,7 @@
3671
3719
  exports.getBannersBannerListUrl = getBannersBannerListUrl;
3672
3720
  exports.getBannersMenuItem = getBannersMenuItem;
3673
3721
  exports.getBannersZoneListUrl = getBannersZoneListUrl;
3722
+ exports.getZoneFields = getZoneFields;
3674
3723
  exports.getZones = getZones;
3675
3724
  exports.updateBanner = updateBanner;
3676
3725
 
@@ -1,5 +1,5 @@
1
1
  import { ResponseBody } from '@tager/admin-services';
2
- import { Zone } from '../typings/zones';
2
+ import { Zone, ZoneFields } from '../typings/zones';
3
3
  import { Banner, BannerPayload } from '../typings/banners';
4
4
  /** Zones **/
5
5
  export declare function getZones(params?: {
@@ -7,6 +7,7 @@ export declare function getZones(params?: {
7
7
  pageNumber?: number;
8
8
  pageSize?: number;
9
9
  }): Promise<ResponseBody<Zone[]>>;
10
+ export declare function getZoneFields(zoneId: string): Promise<ResponseBody<ZoneFields>>;
10
11
  /** Banners **/
11
12
  export declare function getBanners(params?: {
12
13
  query?: string;
@@ -1,5 +1,6 @@
1
1
  import { FileType, Nullable } from '@tager/admin-services';
2
2
  import { OptionType, SingleFileInputValueType } from '@tager/admin-ui';
3
+ import { FieldShortType, FieldUnion, IncomingValueUnion, OutgoingValueUnion } from '@tager/admin-dynamic-field';
3
4
  export declare enum Status {
4
5
  Waiting = "WAITING",
5
6
  Archived = "ARCHIVED",
@@ -18,17 +19,19 @@ export interface Banner {
18
19
  dateEnd: Nullable<string>;
19
20
  disabled: boolean;
20
21
  comment: Nullable<string>;
22
+ fields: FieldShortType<IncomingValueUnion>[];
21
23
  }
22
24
  export interface BannerFormValues {
23
25
  link: Nullable<string>;
24
26
  image: Nullable<SingleFileInputValueType>;
25
27
  bannerZone: Nullable<OptionType>;
26
- priority: number;
28
+ priority: string;
27
29
  openNewTab: boolean;
28
30
  dateStart: string;
29
31
  dateEnd: string;
30
32
  disabled: boolean;
31
33
  comment: string;
34
+ fields: FieldUnion[];
32
35
  }
33
36
  export interface BannerPayload {
34
37
  link: Nullable<string>;
@@ -40,4 +43,5 @@ export interface BannerPayload {
40
43
  dateEnd: Nullable<string>;
41
44
  disabled: boolean;
42
45
  comment: string;
46
+ fields: FieldShortType<OutgoingValueUnion>[];
43
47
  }
@@ -1,5 +1,9 @@
1
+ import { FieldConfigUnion } from '@tager/admin-dynamic-field';
1
2
  export interface Zone {
2
3
  id: string;
3
4
  name: string;
4
5
  bannersCount: number;
5
6
  }
7
+ export interface ZoneFields extends Zone {
8
+ fields: FieldConfigUnion[];
9
+ }