web/satellite: Setting.vue migrated to use composition api

added useLoading composable to get rid or repetative same code usage;

Change-Id: I3524efdb1919759046bbf11fe3510f8044adc828
This commit is contained in:
NickolaiYurchenko 2023-01-12 16:55:04 +02:00
parent a7fc884a2c
commit 86fb188be6
6 changed files with 170 additions and 171 deletions

View File

@ -7,16 +7,7 @@
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
/**
* AccountArea is a container for all account related routes.
*/
// @vue/component
@Component
export default class AccountArea extends Vue {}
</script>
<script setup lang="ts"></script>
<style scoped lang="scss">
::-webkit-scrollbar,

View File

@ -82,13 +82,15 @@
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
<script setup lang="ts">
import { computed, onMounted } from 'vue';
import { USER_ACTIONS } from '@/store/modules/users';
import { User } from '@/types/users';
import { APP_STATE_MUTATIONS } from '@/store/mutationConstants';
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
import { useNotify, useStore } from '@/utils/hooks';
import { useLoading } from '@/composables/useLoading';
import VButton from '@/components/common/VButton.vue';
@ -96,110 +98,93 @@ import ChangePasswordIcon from '@/../static/images/account/profile/changePasswor
import EmailIcon from '@/../static/images/account/profile/email.svg';
import EditIcon from '@/../static/images/common/edit.svg';
// @vue/component
@Component({
components: {
EditIcon,
ChangePasswordIcon,
EmailIcon,
VButton,
},
})
export default class SettingsArea extends Vue {
public isLoading = false;
const store = useStore();
const notify = useNotify();
const { isLoading, withLoading } = useLoading();
/**
* Lifecycle hook after initial render where user info is fetching.
*/
public mounted(): void {
this.$store.dispatch(USER_ACTIONS.GET);
}
/**
* Returns user info from store.
*/
const user = computed((): User => {
return store.getters.user;
});
/**
* Generates user's MFA secret and opens popup.
*/
public async enableMFA(): Promise<void> {
if (this.isLoading) return;
/**
* Returns first letter of user name.
*/
const avatarLetter = computed((): string => {
return store.getters.userName.slice(0, 1).toUpperCase();
});
this.isLoading = true;
try {
await this.$store.dispatch(USER_ACTIONS.GENERATE_USER_MFA_SECRET);
this.toggleEnableMFAModal();
} catch (error) {
await this.$notify.error(error.message, AnalyticsErrorEventSource.ACCOUNT_SETTINGS_AREA);
}
this.isLoading = false;
}
/**
* Toggles generate new MFA recovery codes popup visibility.
*/
public async generateNewMFARecoveryCodes(): Promise<void> {
if (this.isLoading) return;
this.isLoading = true;
try {
await this.$store.dispatch(USER_ACTIONS.GENERATE_USER_MFA_RECOVERY_CODES);
this.toggleMFACodesModal();
} catch (error) {
await this.$notify.error(error.message, AnalyticsErrorEventSource.ACCOUNT_SETTINGS_AREA);
}
this.isLoading = false;
}
/**
* Toggles enable MFA modal visibility.
*/
public toggleEnableMFAModal(): void {
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_ENABLE_MFA_MODAL_SHOWN);
}
/**
* Toggles disable MFA modal visibility.
*/
public toggleDisableMFAModal(): void {
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_DISABLE_MFA_MODAL_SHOWN);
}
/**
* Toggles MFA recovery codes modal visibility.
*/
public toggleMFACodesModal(): void {
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_MFA_RECOVERY_MODAL_SHOWN);
}
/**
* Opens change password popup.
*/
public toggleChangePasswordModal(): void {
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_CHANGE_PASSWORD_MODAL_SHOWN);
}
/**
* Opens edit account info modal.
*/
public toggleEditProfileModal(): void {
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_EDIT_PROFILE_MODAL_SHOWN);
}
/**
* Returns user info from store.
*/
public get user(): User {
return this.$store.getters.user;
}
/**
* Returns first letter of user name.
*/
public get avatarLetter(): string {
return this.$store.getters.userName.slice(0, 1).toUpperCase();
}
/**
* Toggles enable MFA modal visibility.
*/
function toggleEnableMFAModal(): void {
store.commit(APP_STATE_MUTATIONS.TOGGLE_ENABLE_MFA_MODAL_SHOWN);
}
/**
* Toggles disable MFA modal visibility.
*/
function toggleDisableMFAModal(): void {
store.commit(APP_STATE_MUTATIONS.TOGGLE_DISABLE_MFA_MODAL_SHOWN);
}
/**
* Toggles MFA recovery codes modal visibility.
*/
function toggleMFACodesModal(): void {
store.commit(APP_STATE_MUTATIONS.TOGGLE_MFA_RECOVERY_MODAL_SHOWN);
}
/**
* Opens change password popup.
*/
function toggleChangePasswordModal(): void {
store.commit(APP_STATE_MUTATIONS.TOGGLE_CHANGE_PASSWORD_MODAL_SHOWN);
}
/**
* Opens edit account info modal.
*/
function toggleEditProfileModal(): void {
store.commit(APP_STATE_MUTATIONS.TOGGLE_EDIT_PROFILE_MODAL_SHOWN);
}
/**
* Generates user's MFA secret and opens popup.
*/
async function enableMFA(): Promise<void> {
await withLoading(async () => {
try {
await store.dispatch(USER_ACTIONS.GENERATE_USER_MFA_SECRET);
toggleEnableMFAModal();
} catch (error) {
await notify.error(error.message, AnalyticsErrorEventSource.ACCOUNT_SETTINGS_AREA);
}
});
}
/**
* Toggles generate new MFA recovery codes popup visibility.
*/
async function generateNewMFARecoveryCodes(): Promise<void> {
await withLoading(async () => {
try {
await store.dispatch(USER_ACTIONS.GENERATE_USER_MFA_RECOVERY_CODES);
toggleMFACodesModal();
} catch (error) {
await notify.error(error.message, AnalyticsErrorEventSource.ACCOUNT_SETTINGS_AREA);
}
});
}
/**
* Lifecycle hook after initial render where user info is fetching.
*/
onMounted(() => {
store.dispatch(USER_ACTIONS.GET);
});
</script>
<style scoped lang="scss">

View File

@ -35,6 +35,7 @@ import { PAYMENTS_ACTIONS } from '@/store/modules/payments';
import { AnalyticsHttpApi } from '@/api/analytics';
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
import { useNotify, useStore } from '@/utils/hooks';
import { useLoading } from '@/composables/useLoading';
import VInput from '@/components/common/VInput.vue';
import ValidationMessage from '@/components/common/ValidationMessage.vue';
@ -42,6 +43,7 @@ import VButton from '@/components/common/VButton.vue';
const store = useStore();
const notify = useNotify();
const { isLoading, withLoading } = useLoading();
const emit = defineEmits(['close']);
@ -49,7 +51,6 @@ const showValidationMessage = ref<boolean>(false);
const isCodeValid = ref<boolean>(false);
const errorMessage = ref<string>('');
const couponCode = ref<string>('');
const isLoading = ref<boolean>(false);
const analytics = new AnalyticsHttpApi();
@ -61,22 +62,20 @@ function setCouponCode(value: string): void {
* Check if coupon code is valid
*/
async function applyCouponCode(): Promise<void> {
if (isLoading.value) return;
isLoading.value = true;
try {
await store.dispatch(PAYMENTS_ACTIONS.APPLY_COUPON_CODE, couponCode.value);
await notify.success('Coupon Added!');
emit('close');
} catch (error) {
errorMessage.value = error.message;
isCodeValid.value = false;
showValidationMessage.value = true;
await analytics.errorEventTriggered(AnalyticsErrorEventSource.BILLING_APPLY_COUPON_CODE_INPUT);
} finally {
isLoading.value = false;
}
await withLoading(async () => {
try {
await store.dispatch(PAYMENTS_ACTIONS.APPLY_COUPON_CODE, couponCode.value);
await notify.success('Coupon Added!');
emit('close');
} catch (error) {
errorMessage.value = error.message;
isCodeValid.value = false;
showValidationMessage.value = true;
await analytics.errorEventTriggered(AnalyticsErrorEventSource.BILLING_APPLY_COUPON_CODE_INPUT);
} finally {
isLoading.value = false;
}
});
}
</script>

View File

@ -19,9 +19,12 @@
import { computed, ref } from 'vue';
import { OnPageClickCallback } from '@/types/pagination';
import { useLoading } from '@/composables/useLoading';
import PaginationRightIcon from '@/../static/images/common/tablePaginationArrowRight.svg';
const { withLoading } = useLoading();
const props = withDefaults(defineProps<{
totalPageCount?: number;
limit?: number;
@ -35,7 +38,6 @@ const props = withDefaults(defineProps<{
});
const currentPageNumber = ref<number>(1);
const isLoading = ref<boolean>(false);
const label = computed((): string => {
const currentMaxPage = currentPageNumber.value * props.limit > props.totalItemsCount ?
@ -56,28 +58,28 @@ const isLastPage = computed((): boolean => {
* nextPage fires after 'next' arrow click.
*/
async function nextPage(): Promise<void> {
if (isLastPage.value || isLoading.value) {
return;
}
await withLoading(async () => {
if (isLastPage.value) {
return;
}
isLoading.value = true;
await props.onPageClickCallback(currentPageNumber.value + 1);
incrementCurrentPage();
isLoading.value = false;
await props.onPageClickCallback(currentPageNumber.value + 1);
incrementCurrentPage();
});
}
/**
* prevPage fires after 'previous' arrow click.
*/
async function prevPage(): Promise<void> {
if (isFirstPage.value || isLoading.value) {
return;
}
await withLoading(async () => {
if (isFirstPage.value) {
return;
}
isLoading.value = true;
await props.onPageClickCallback(currentPageNumber.value - 1);
decrementCurrentPage();
isLoading.value = false;
await props.onPageClickCallback(currentPageNumber.value - 1);
decrementCurrentPage();
});
}
function incrementCurrentPage(): void {

View File

@ -34,6 +34,7 @@
import { computed, onMounted, ref, watch } from 'vue';
import { OnPageClickCallback, Page } from '@/types/pagination';
import { useLoading } from '@/composables/useLoading';
import PagesBlock from '@/components/common/PagesBlock.vue';
@ -44,14 +45,16 @@ const MAX_PAGES_PER_BLOCK = 3;
const MAX_PAGES_OFF_BLOCKS = 6;
const props = withDefaults(defineProps<{
onPageClickCallback: OnPageClickCallback;
onPageClickCallback?: OnPageClickCallback;
totalPageCount?: number;
}>(), {
totalPageCount: 0,
onPageClickCallback: () => () => {},
});
const { withLoading } = useLoading();
const currentPageNumber = ref<number>(1);
const isLoading = ref<boolean>(false);
const pagesArray = ref<Page[]>([]);
const firstBlockPages = ref<Page[]>([]);
const middleBlockPages = ref<Page[]>([]);
@ -169,45 +172,41 @@ function setCurrentPage(pageNumber: number): void {
* onPageClick fires after concrete page click.
*/
async function onPageClick(page: number): Promise<void> {
if (isLoading.value) {
return;
}
isLoading.value = true;
await props.onPageClickCallback(page);
setCurrentPage(page);
reorganizePageBlocks();
isLoading.value = false;
await withLoading(async () => {
await props.onPageClickCallback(page);
setCurrentPage(page);
reorganizePageBlocks();
});
}
/**
* nextPage fires after 'next' arrow click.
*/
async function nextPage(): Promise<void> {
if (isLastPage || isLoading.value) {
return;
}
await withLoading(async () => {
if (isLastPage) {
return;
}
isLoading.value = true;
await props.onPageClickCallback(currentPageNumber.value + 1);
incrementCurrentPage();
reorganizePageBlocks();
isLoading.value = false;
await props.onPageClickCallback(currentPageNumber.value + 1);
incrementCurrentPage();
reorganizePageBlocks();
});
}
/**
* prevPage fires after 'previous' arrow click.
*/
async function prevPage(): Promise<void> {
if (isFirstPage || isLoading.value) {
return;
}
await withLoading(async () => {
if (isFirstPage) {
return;
}
isLoading.value = true;
await props.onPageClickCallback(currentPageNumber.value - 1);
decrementCurrentPage();
reorganizePageBlocks();
isLoading.value = false;
await props.onPageClickCallback(currentPageNumber.value - 1);
decrementCurrentPage();
reorganizePageBlocks();
});
}
/**

View File

@ -0,0 +1,23 @@
// Copyright (C) 2023 Storj Labs, Inc.
// See LICENSE for copying information.
import { ref } from 'vue';
export function useLoading() {
const isLoading = ref<boolean>(false);
async function withLoading(callback): Promise<void> {
if (isLoading.value) return;
isLoading.value = true;
await callback();
isLoading.value = false;
}
return {
isLoading,
withLoading,
};
}