Files
ezbookkeeping/src/views/mobile/SignupPage.vue
T

314 lines
14 KiB
Vue

<template>
<f7-page>
<f7-navbar>
<f7-nav-left :back-link="tt('Back')"></f7-nav-left>
<f7-nav-title :title="tt('Sign Up')"></f7-nav-title>
<f7-nav-right>
<f7-link icon-f7="checkmark_alt" :class="{ 'disabled': inputIsEmpty || submitting }" @click="submit"></f7-link>
</f7-nav-right>
</f7-navbar>
<f7-list form strong inset dividers class="margin-vertical">
<f7-list-input
type="text"
autocomplete="username"
autocapitalize="none"
autocorrect="off"
spellcheck="false"
inputmode="email"
clear-button
:label="tt('Username')"
:placeholder="tt('Your username')"
v-model:value="user.username"
></f7-list-input>
<f7-list-input
type="password"
autocomplete="new-password"
clear-button
:label="tt('Password')"
:placeholder="tt('Your password, at least 6 characters')"
v-model:value="user.password"
></f7-list-input>
<f7-list-input
type="password"
autocomplete="new-password"
clear-button
:label="tt('Confirm Password')"
:placeholder="tt('Re-enter the password')"
v-model:value="user.confirmPassword"
></f7-list-input>
<f7-list-input
type="email"
autocomplete="email"
clear-button
:label="tt('E-mail')"
:placeholder="tt('Your email address')"
v-model:value="user.email"
></f7-list-input>
<f7-list-input
type="text"
autocomplete="nickname"
clear-button
:label="tt('Nickname')"
:placeholder="tt('Your nickname')"
v-model:value="user.nickname"
></f7-list-input>
<f7-list-item class="ebk-list-item-error-info" v-if="inputIsInvalid" :footer="tt(inputInvalidProblemMessage)"></f7-list-item>
</f7-list>
<f7-list strong inset dividers class="margin-vertical">
<f7-list-item
class="list-item-with-header-and-title list-item-no-item-after"
link="#"
:header="languageTitle"
:title="currentLanguageName"
@click="showLanguagePopup = true"
>
<list-item-selection-popup value-type="item"
key-field="languageTag" value-field="languageTag"
title-field="nativeDisplayName" after-field="displayName"
:title="languageTitle"
:enable-filter="true"
:filter-placeholder="tt('Language')"
:filter-no-items-text="tt('No results')"
:items="allLanguages"
v-model:show="showLanguagePopup"
v-model="currentLocale">
</list-item-selection-popup>
</f7-list-item>
<f7-list-item
class="list-item-with-header-and-title list-item-no-item-after"
link="#"
:header="tt('Default Currency')"
@click="showDefaultCurrencyPopup = true"
>
<template #title>
<f7-block class="no-padding no-margin">
<span>{{ getCurrencyName(user.defaultCurrency) }}&nbsp;</span>
<small class="smaller">{{ user.defaultCurrency }}</small>
</f7-block>
</template>
<list-item-selection-popup value-type="item"
key-field="currencyCode" value-field="currencyCode"
title-field="displayName" after-field="currencyCode"
:title="tt('Default Currency')"
:enable-filter="true"
:filter-placeholder="tt('Currency')"
:filter-no-items-text="tt('No results')"
:items="allCurrencies"
v-model:show="showDefaultCurrencyPopup"
v-model="user.defaultCurrency">
</list-item-selection-popup>
</f7-list-item>
<f7-list-item
link="#"
class="list-item-with-header-and-title list-item-no-item-after"
:header="tt('First Day of Week')"
:title="currentDayOfWeekName"
@click="showFirstDayOfWeekPopup = true"
>
<list-item-selection-popup value-type="item"
key-field="type" value-field="type"
title-field="displayName"
:title="tt('First Day of Week')"
:enable-filter="true"
:filter-placeholder="tt('Date')"
:filter-no-items-text="tt('No results')"
:items="allWeekDays"
v-model:show="showFirstDayOfWeekPopup"
v-model="user.firstDayOfWeek">
</list-item-selection-popup>
</f7-list-item>
</f7-list>
<f7-list strong inset dividers class="margin-vertical">
<f7-list-item :title="tt('Use preset transaction categories')" link="#" @click="showPresetCategories = true">
<f7-toggle :checked="usePresetCategories" @toggle:change="usePresetCategories = $event"></f7-toggle>
</f7-list-item>
</f7-list>
<f7-popup push :close-on-escape="false" :opened="showPresetCategories"
@popup:closed="showPresetCategories = false">
<f7-page>
<f7-navbar>
<f7-nav-left>
<f7-link popup-close icon-f7="xmark"></f7-link>
</f7-nav-left>
<f7-nav-title :title="tt('Preset Categories')"></f7-nav-title>
<f7-nav-right class="navbar-compact-icons">
<f7-link icon-f7="ellipsis" @click="showPresetCategoriesMoreActionSheet = true"></f7-link>
<f7-link close @click="usePresetCategories = true; showPresetCategories = false" v-if="!usePresetCategories">{{ tt('Enable') }}</f7-link>
<f7-link close @click="usePresetCategories = false; showPresetCategories = false" v-if="usePresetCategories">{{ tt('Disable') }}</f7-link>
</f7-nav-right>
</f7-navbar>
<f7-block class="no-padding no-margin"
:key="categoryType" v-for="(categories, categoryType) in allPresetCategories">
<f7-block-title class="margin-top margin-horizontal">{{ getCategoryTypeName(parseInt(categoryType)) }}</f7-block-title>
<f7-list strong inset dividers v-if="showPresetCategories">
<f7-list-item :title="category.name"
:accordion-item="!!category.subCategories.length"
:key="idx"
v-for="(category, idx) in categories">
<template #media>
<ItemIcon icon-type="category" :icon-id="category.icon" :color="category.color"></ItemIcon>
</template>
<f7-accordion-content v-if="category.subCategories.length" class="padding-inline-start-half">
<f7-list>
<f7-list-item :title="subCategory.name"
:key="subIdx"
v-for="(subCategory, subIdx) in category.subCategories">
<template #media>
<ItemIcon icon-type="category" :icon-id="subCategory.icon" :color="subCategory.color"></ItemIcon>
</template>
</f7-list-item>
</f7-list>
</f7-accordion-content>
</f7-list-item>
</f7-list>
</f7-block>
</f7-page>
<f7-actions close-by-outside-click close-on-escape :opened="showPresetCategoriesMoreActionSheet" @actions:closed="showPresetCategoriesMoreActionSheet = false">
<f7-actions-group>
<f7-actions-button @click="showPresetCategoriesChangeLocaleSheet = true">{{ tt('Change Language') }}</f7-actions-button>
</f7-actions-group>
<f7-actions-group>
<f7-actions-button bold close>{{ tt('Cancel') }}</f7-actions-button>
</f7-actions-group>
</f7-actions>
<list-item-selection-sheet value-type="item"
key-field="languageTag" value-field="languageTag"
title-field="nativeDisplayName" after-field="displayName"
:items="allLanguages"
v-model:show="showPresetCategoriesChangeLocaleSheet"
v-model="currentLocale">
</list-item-selection-sheet>
</f7-popup>
</f7-page>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import type { Router } from 'framework7/types';
import type { LanguageOption } from '@/locales/index.ts';
import { useI18n } from '@/locales/helpers.ts';
import { useI18nUIComponents, showLoading, hideLoading } from '@/lib/ui/mobile.ts';
import { useSignupPageBase } from '@/views/base/SignupPageBase.ts';
import { useRootStore } from '@/stores/index.ts';
import type { TypeAndDisplayName } from '@/core/base.ts';
import type { LocalizedCurrencyInfo } from '@/core/currency.ts';
import { type LocalizedPresetCategory } from '@/core/category.ts';
import { findDisplayNameByType, categorizedArrayToPlainArray } from '@/lib/common.ts';
import { isUserLogined } from '@/lib/userstate.ts';
const props = defineProps<{
f7router: Router.Router;
}>();
const { tt, getAllLanguageOptions, getAllCurrencies, getAllWeekDays, getAllTransactionDefaultCategories, getCurrencyName } = useI18n();
const { showAlert, showToast } = useI18nUIComponents();
const {
user,
submitting,
languageTitle,
currentLocale,
currentLanguageName,
inputEmptyProblemMessage,
inputInvalidProblemMessage,
inputIsEmpty,
inputIsInvalid,
getCategoryTypeName,
doAfterSignupSuccess
} = useSignupPageBase();
const rootStore = useRootStore();
const usePresetCategories = ref<boolean>(false);
const showLanguagePopup = ref<boolean>(false);
const showDefaultCurrencyPopup = ref<boolean>(false);
const showFirstDayOfWeekPopup = ref<boolean>(false);
const showPresetCategories = ref<boolean>(false);
const showPresetCategoriesMoreActionSheet = ref<boolean>(false);
const showPresetCategoriesChangeLocaleSheet = ref<boolean>(false);
const allLanguages = computed<LanguageOption[]>(() => getAllLanguageOptions(false));
const allCurrencies = computed<LocalizedCurrencyInfo[]>(() => getAllCurrencies());
const allWeekDays = computed<TypeAndDisplayName[]>(() => getAllWeekDays());
const allPresetCategories = computed<Record<string, LocalizedPresetCategory[]>>(() => getAllTransactionDefaultCategories(0, currentLocale.value));
const currentDayOfWeekName = computed<string | null>(() => findDisplayNameByType(allWeekDays.value, user.value.firstDayOfWeek));
function submit(): void {
const router = props.f7router;
const problemMessage = inputEmptyProblemMessage.value || inputInvalidProblemMessage.value;
if (problemMessage) {
showAlert(problemMessage);
return;
}
submitting.value = true;
showLoading(() => submitting.value);
let presetCategories: LocalizedPresetCategory[] = [];
if (usePresetCategories.value) {
presetCategories = categorizedArrayToPlainArray(allPresetCategories.value);
}
rootStore.register({
user: user.value,
presetCategories: presetCategories
}).then(response => {
if (!isUserLogined()) {
submitting.value = false;
hideLoading();
if (usePresetCategories.value && !response.presetCategoriesSaved) {
showToast('You have been successfully registered, but there was an failure when adding preset categories. You can re-add preset categories in settings page anytime.', 5000);
} else if (response.needVerifyEmail) {
showToast('You have been successfully registered. An account activation link has been sent to your email address, please activate your account first.', 5000);
} else {
showToast('You have been successfully registered');
}
router.navigate('/');
return;
}
doAfterSignupSuccess(response);
submitting.value = false;
hideLoading();
if (usePresetCategories.value && !response.presetCategoriesSaved) {
showToast('You have been successfully registered, but there was an failure when adding preset categories. You can re-add preset categories in settings page anytime.');
} else {
showToast('You have been successfully registered');
}
router.navigate('/');
}).catch(error => {
submitting.value = false;
hideLoading();
if (!error.processed) {
showToast(error.message || error);
}
});
}
</script>