@@ -12,16 +12,16 @@ import {PrimaryButton} from "../../../../shared/components/atoms/button-primary"
1212import {SecondaryButton } from " ../../../../shared/components/atoms/button-secondary" ;
1313import {Toast } from " ../../../../shared/modules/toast" ;
1414import apolloClient from " ../../../../../apollo-client" ;
15- import { getProductPropertiesRuleQuery , productPropertiesRulesQuery } from " ../../../../shared/api/queries/properties.js" ;
15+ import { getProductPropertiesRuleQuery , productPropertiesRulesWithUsageCountQuery } from " ../../../../shared/api/queries/properties.js" ;
1616import { completeCreateProductPropertiesRuleMutation , completeUpdateProductPropertiesRuleMutation , deleteProductPropertiesRuleMutation } from " ../../../../shared/api/mutations/properties.js" ;
1717import { integrationsQuery } from " ../../../../shared/api/queries/integrations.js" ;
1818import {DangerButton } from " ../../../../shared/components/atoms/button-danger" ;
1919import {FormType } from " ../../../../shared/components/organisms/general-form/formConfig" ;
2020import {ApolloAlertMutation } from " ../../../../shared/components/molecules/apollo-alert-mutation" ;
2121import { Property } from " ../../../../shared/components/organisms/product-properties-configurator/ProductPropertiesConfigurator.vue" ;
22- import {Loader } from " ../../../../shared/components/atoms/loader" ;
2322import {Link } from " ../../../../shared/components/atoms/link" ;
2423import {Button } from " ../../../../shared/components/atoms/button" ;
24+ import { LocalLoader } from " ../../../../shared/components/atoms/local-loader" ;
2525import Swal , { SweetAlertOptions } from " sweetalert2" ;
2626
2727interface Item {
@@ -55,7 +55,9 @@ const initialProductType = ref<{ id: string; value: string } | null>(null);
5555const initialItems: Ref <Property []> = ref ([]);
5656const updatedAddedProperties: Ref <Property []> = ref ([]);
5757const propertiesItemsMap: Ref <Record <string , Item >> = ref ({});
58- const loading = ref (false );
58+ const integrationsLoading = ref (false );
59+ const rightLoading = ref (false );
60+ const saveLoading = ref (false );
5961const requireEanCode = ref (false );
6062const selectedSalesChannel = ref <' default' | string >(' default' );
6163const previousSalesChannel = ref <' default' | string >(' default' );
@@ -76,6 +78,10 @@ const secondaryButtonLabel = computed(() =>
7678 t (currentRuleId .value ? ' shared.button.saveAndContinue' : ' shared.button.createAndContinue' )
7779);
7880
81+ const disableActions = computed (() =>
82+ integrationsLoading .value || rightLoading .value || saveLoading .value
83+ );
84+
7985const getCacheKey = (salesChannelId : string | null | undefined ) =>
8086 salesChannelId ?? ' default' ;
8187
@@ -207,7 +213,7 @@ const fetchRuleBySalesChannel = async (channelKey: string): Promise<RuleCacheEnt
207213 }
208214
209215 const { data } = await apolloClient .query ({
210- query: productPropertiesRulesQuery ,
216+ query: productPropertiesRulesWithUsageCountQuery ,
211217 variables: { filter , first: 1 },
212218 fetchPolicy: ' network-only' ,
213219 });
@@ -233,6 +239,7 @@ const ensureDefaultRule = async () => {
233239};
234240
235241const loadSalesChannels = async () => {
242+ integrationsLoading .value = true ;
236243 try {
237244 const { data } = await apolloClient .query ({ query: integrationsQuery , fetchPolicy: ' cache-first' });
238245 const nodes = data ?.integrations ?.edges ?.map ((edge : any ) => edge .node ) ?? [];
@@ -263,6 +270,8 @@ const loadSalesChannels = async () => {
263270 rawSalesChannels .value = Array .from (optionsMap .values ());
264271 } catch (_error ) {
265272 rawSalesChannels .value = [... rawSalesChannels .value ];
273+ } finally {
274+ integrationsLoading .value = false ;
266275 }
267276};
268277
@@ -322,6 +331,10 @@ const hasUnsavedChanges = computed(() => {
322331});
323332
324333const handleSalesChannelUpdated = async (newValue : string ) => {
334+ if (disableActions .value ) {
335+ return ;
336+ }
337+
325338 const normalizedValue = newValue && newValue !== ' ' ? newValue : ' default' ;
326339
327340 if (normalizedValue === selectedSalesChannel .value ) {
@@ -362,7 +375,8 @@ const handleSalesChannelUpdated = async (newValue: string) => {
362375 selectedSalesChannel .value = normalizedValue ;
363376 previousSalesChannel .value = normalizedValue ;
364377
365- loading .value = true ;
378+ integrationsLoading .value = true ;
379+ rightLoading .value = true ;
366380 try {
367381 let entry: RuleCacheEntry | null = rulesCache .value [normalizedValue ] ?? null ;
368382 if (! entry ) {
@@ -404,7 +418,8 @@ const handleSalesChannelUpdated = async (newValue: string) => {
404418 await updateRouteId (entry .id );
405419 }
406420 } finally {
407- loading .value = false ;
421+ integrationsLoading .value = false ;
422+ rightLoading .value = false ;
408423 }
409424};
410425
@@ -467,7 +482,7 @@ const persistRule = async (): Promise<RuleCacheEntry | null> => {
467482};
468483
469484const fetchData = async () => {
470- loading .value = true ;
485+ rightLoading .value = true ;
471486 propertiesItemsMap .value = {};
472487 initialItems .value = [];
473488 updatedAddedProperties .value = [];
@@ -497,33 +512,41 @@ const fetchData = async () => {
497512 await ensureDefaultRule ();
498513 }
499514 } finally {
500- loading .value = false ;
515+ rightLoading .value = false ;
501516 }
502517};
503518
504519const handleSave = () => saveMutations (false );
505520const handleSaveAndContinue = () => saveMutations (true );
506521const saveMutations = async (continueEditing = false ) => {
522+ if (disableActions .value ) {
523+ return ;
524+ }
507525
508526 if (initialProductType .value == null ) {
509527 Toast .error (t (' properties.rule.error.noProductType' ));
510528 return
511529 }
512530
513- const isCreateAction = ! currentRuleId .value ;
514- const entry = await persistRule ();
531+ saveLoading .value = true ;
532+ try {
533+ const isCreateAction = ! currentRuleId .value ;
534+ const entry = await persistRule ();
515535
516- if (! entry ) {
517- Toast .error (t (' shared.alert.toast.unexpectedResult' ));
518- return ;
519- }
536+ if (! entry ) {
537+ Toast .error (t (' shared.alert.toast.unexpectedResult' ));
538+ return ;
539+ }
520540
521- Toast .success (t (isCreateAction ? ' properties.rule.alert.createSuccess' : ' properties.rule.alert.updateSuccess' ))
522- if (continueEditing ) {
523- return
524- }
541+ Toast .success (t (isCreateAction ? ' properties.rule.alert.createSuccess' : ' properties.rule.alert.updateSuccess' ))
542+ if (continueEditing ) {
543+ return
544+ }
525545
526- router .push ({name: ' properties.rule.list' });
546+ router .push ({name: ' properties.rule.list' });
547+ } finally {
548+ saveLoading .value = false ;
549+ }
527550
528551};
529552
@@ -575,27 +598,31 @@ watch(
575598 { path: { name: 'properties.rule.edit' }, name: t('properties.rule.edit.title') }]" />
576599 </template >
577600
578- <template v-slot :content >
601+ <template v-slot :content >
579602 <Card class =" mt-2 p-4" >
580- <Loader :loading =" loading" />
603+ <div v-if =" !initialProductType" class =" py-12 flex items-center justify-center" >
604+ <LocalLoader :loading =" rightLoading || integrationsLoading" />
605+ </div >
581606 <ProductPropertiesConfigurator
582607 v-if =" initialProductType"
583608 :added-properties =" initialItems"
584609 :product-type =" initialProductType"
585610 :require-ean-code =" requireEanCode"
586611 :sales-channel-options =" salesChannelOptions"
587612 :selected-sales-channel =" selectedSalesChannel"
613+ :integrations-loading =" integrationsLoading"
614+ :right-loading =" rightLoading || saveLoading"
588615 @update:added-properties =" handleAddedProperties"
589616 @update:require-ean-code =" handleRequireEanCodeUpdated"
590617 @update:sales-channel =" handleSalesChannelUpdated"
591618 />
592619
593620 <div class =" flex items-center justify-end gap-x-3 border-t border-gray-900/10 px-4 py-4 sm:px-8" >
594- <CancelButton @click =" () => router.push({ name: 'properties.rule.list' })" >
621+ <CancelButton :disabled = " disableActions " @click =" () => router.push({ name: 'properties.rule.list' })" >
595622 {{ t('shared.button.cancel') }}
596623 </CancelButton >
597624 <Link v-if =" currentRuleId" :path =" { name: 'properties.rule.show', params: { id: currentRuleId } }" >
598- <Button type =" button" class =" button rounded-md px-3 py-2 text-sm font-semibold text-white shadow-sm btn-info " >
625+ <Button type =" button" :disabled = " disableActions " class =" button rounded-md px-3 py-2 text-sm font-semibold text-white shadow-sm btn-info " >
599626 {{ t('shared.button.show') }}
600627 </Button >
601628 </Link >
@@ -606,13 +633,13 @@ watch(
606633 @done =" handleDelete"
607634 >
608635 <template v-slot =" { loading: deleting , confirmAndMutate } " >
609- <DangerButton ref =" deleteButtonRef" :disabled =" deleting" @click =" confirmAndMutate" >{{ t('shared.button.delete') }}</DangerButton >
636+ <DangerButton ref =" deleteButtonRef" :disabled =" deleting || disableActions " @click =" confirmAndMutate" >{{ t('shared.button.delete') }}</DangerButton >
610637 </template >
611638 </ApolloAlertMutation >
612- <SecondaryButton @click =" handleSaveAndContinue" >
639+ <SecondaryButton :disabled = " disableActions " :loading = " saveLoading " @click =" handleSaveAndContinue" >
613640 {{ secondaryButtonLabel }}
614641 </SecondaryButton >
615- <PrimaryButton @click =" handleSave" >
642+ <PrimaryButton :disabled = " disableActions " :loading = " saveLoading " @click =" handleSave" >
616643 {{ primaryButtonLabel }}
617644 </PrimaryButton >
618645 </div >
0 commit comments