import { ref, computed } from 'vue'; import { defineStore } from 'pinia'; import { useSettingsStore } from './setting.ts'; import { type WeekDayValue, WeekDay } from '@/core/datetime.ts'; import { FiscalYearStart } from '@/core/fiscalyear.ts'; import { KnownFileType } from '@/core/file.ts'; import type { ApplicationCloudSetting } from '@/core/setting.ts'; import { type UserBasicInfo, type UserProfileResponse, type UserProfileUpdateResponse, User, EMPTY_USER_BASIC_INFO } from '@/models/user.ts'; import type { ExportTransactionDataRequest, DataStatisticsResponse } from '@/models/data_management.ts'; import { isObject, isString, isNumber } from '@/lib/common.ts'; import { getCurrentUserInfo, updateCurrentUserInfo, clearCurrentUserInfo } from '@/lib/userstate.ts'; import logger from '@/lib/logger.ts'; import services from '@/lib/services.ts'; export const useUserStore = defineStore('user', () => { const settingsStore = useSettingsStore(); const currentUserBasicInfo = ref(getCurrentUserInfo()); const currentUserNickname = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return userInfo.nickname || userInfo.username || null; }); const currentUserAvatar = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return getUserAvatarUrl(userInfo, false); }); const currentUserDefaultAccountId = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return userInfo.defaultAccountId; }); const currentUserLanguage = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return userInfo.language; }); const currentUserDefaultCurrency = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return userInfo.defaultCurrency || settingsStore.localeDefaultSettings.currency; }); const currentUserFirstDayOfWeek = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return isNumber(userInfo.firstDayOfWeek) && WeekDay.valueOf(userInfo.firstDayOfWeek) ? userInfo.firstDayOfWeek as WeekDayValue : settingsStore.localeDefaultSettings.firstDayOfWeek; }); const currentUserFiscalYearStart = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return isNumber(userInfo.fiscalYearStart) && FiscalYearStart.valueOf(userInfo.fiscalYearStart) ? userInfo.fiscalYearStart : EMPTY_USER_BASIC_INFO.fiscalYearStart; }); const currentUserCalendarDisplayType = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return userInfo.calendarDisplayType; }); const currentUserDateDisplayType = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return userInfo.dateDisplayType; }); const currentUserLongDateFormat = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return userInfo.longDateFormat; }); const currentUserShortDateFormat = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return userInfo.shortDateFormat; }); const currentUserLongTimeFormat = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return userInfo.longTimeFormat; }); const currentUserShortTimeFormat = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return userInfo.shortTimeFormat; }); const currentUserFiscalYearFormat = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return userInfo.fiscalYearFormat; }); const currentUserCurrencyDisplayType = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return userInfo.currencyDisplayType; }); const currentUserNumeralSystem = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return userInfo.numeralSystem; }); const currentUserDecimalSeparator = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return userInfo.decimalSeparator; }); const currentUserDigitGroupingSymbol = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return userInfo.digitGroupingSymbol; }); const currentUserDigitGrouping = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return userInfo.digitGrouping; }); const currentUserCoordinateDisplayType = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return userInfo.coordinateDisplayType; }); const currentUserExpenseAmountColor = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return userInfo.expenseAmountColor; }); const currentUserIncomeAmountColor = computed(() => { const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO; return userInfo.incomeAmountColor; }); function generateNewUserModel(language: string): User { return User.createNewUser(language, settingsStore.localeDefaultSettings.currency, settingsStore.localeDefaultSettings.firstDayOfWeek); } function storeUserBasicInfo(userInfo: UserBasicInfo): void { currentUserBasicInfo.value = userInfo; updateCurrentUserInfo(userInfo); } function resetUserBasicInfo(): void { currentUserBasicInfo.value = null; clearCurrentUserInfo(); } function getCurrentUserProfile(): Promise { return new Promise((resolve, reject) => { services.getProfile().then(response => { const data = response.data; if (!data || !data.success || !data.result) { reject({ message: 'Unable to retrieve user profile' }); return; } resolve(data.result); }).catch(error => { logger.error('failed to retrieve user profile', error); if (error.response && error.response.data && error.response.data.errorMessage) { reject({ error: error.response.data }); } else if (!error.processed) { reject({ message: 'Unable to retrieve user profile' }); } else { reject(error); } }); }); } function updateUserTransactionEditScope({ transactionEditScope }: { transactionEditScope: number }): Promise { return new Promise((resolve, reject) => { services.updateProfile({ transactionEditScope }).then(response => { const data = response.data; if (!data || !data.success || !data.result || !data.result.user || !isObject(data.result.user)) { reject({ message: 'Unable to update editable transaction range' }); return; } storeUserBasicInfo(data.result.user); resolve(data.result); }).catch(error => { logger.error('failed to save editable transaction range', error); if (error.response && error.response.data && error.response.data.errorMessage) { reject({ error: error.response.data }); } else if (!error.processed) { reject({ message: 'Unable to update editable transaction range' }); } else { reject(error); } }); }); } function updateUserAvatar({ avatarFile }: { avatarFile: File }): Promise { return new Promise((resolve, reject) => { services.updateAvatar({ avatarFile }).then(response => { const data = response.data; if (!data || !data.success || !data.result) { reject({ message: 'Unable to update user avatar' }); return; } storeUserBasicInfo(data.result); resolve(data.result); }).catch(error => { logger.error('failed to update user avatar', error); if (error.response && error.response.data && error.response.data.errorMessage) { reject({ error: error.response.data }); } else if (!error.processed) { reject({ message: 'Unable to update user avatar' }); } else { reject(error); } }); }); } function removeUserAvatar(): Promise { return new Promise((resolve, reject) => { services.removeAvatar().then(response => { const data = response.data; if (!data || !data.success || !data.result) { reject({ message: 'Unable to remove user avatar' }); return; } storeUserBasicInfo(data.result); resolve(data.result); }).catch(error => { logger.error('failed to remove user avatar', error); if (error.response && error.response.data && error.response.data.errorMessage) { reject({ error: error.response.data }); } else if (!error.processed) { reject({ message: 'Unable to remove user avatar' }); } else { reject(error); } }); }); } function getUserApplicationCloudSettings(): Promise { return new Promise((resolve, reject) => { services.getUserApplicationCloudSettings().then(response => { const data = response.data; if (!data || !data.success || !data.result) { resolve(data.result); return; } resolve(data.result); }).catch(error => { logger.error('failed to load user synchronized application settings', error); if (error.response && error.response.data && error.response.data.errorMessage) { reject({ error: error.response.data }); } else if (!error.processed) { reject({ message: 'Unable to retrieve user synchronized application settings' }); } else { reject(error); } }); }); } function fullUpdateUserApplicationCloudSettings(enabledSettingKeys: string[]): Promise { const settings = settingsStore.createApplicationCloudSettings(enabledSettingKeys); return new Promise((resolve, reject) => { services.updateUserApplicationCloudSettings({ settings: settings, fullUpdate: true }).then(response => { const data = response.data; if (!data || !data.success || !data.result) { reject({ message: 'Unable to update user synchronized application settings' }); return; } settingsStore.updateApplicationSyncSettingKeys(enabledSettingKeys); resolve(data.result); }).catch(error => { logger.error('failed to update user synchronized application settings', error); if (error.response && error.response.data && error.response.data.errorMessage) { reject({ error: error.response.data }); } else if (!error.processed) { reject({ message: 'Unable to update user synchronized application settings' }); } else { reject(error); } }); }); } function disableUserApplicationCloudSettings(): Promise { return new Promise((resolve, reject) => { services.disableUserApplicationCloudSettings().then(response => { const data = response.data; if (!data || !data.success || !data.result) { reject({ message: 'Unable to disable user synchronized application settings' }); return; } settingsStore.updateApplicationSyncSettingKeys(undefined); resolve(data.result); }).catch(error => { logger.error('failed to disable user synchronized application settings', error); if (error.response && error.response.data && error.response.data.errorMessage) { reject({ error: error.response.data }); } else if (!error.processed) { reject({ message: 'Unable to disable user synchronized application settings' }); } else { reject(error); } }); }); } function getUserDataStatistics(): Promise { return new Promise((resolve, reject) => { services.getUserDataStatistics().then(response => { const data = response.data; if (!data || !data.success || !data.result) { reject({ message: 'Unable to retrieve user statistics data' }); return; } resolve(data.result); }).catch(error => { logger.error('failed to retrieve user statistics data', error); if (error.response && error.response.data && error.response.data.errorMessage) { reject({ error: error.response.data }); } else if (!error.processed) { reject({ message: 'Unable to retrieve user statistics data' }); } else { reject(error); } }); }); } function getExportedUserData(fileType: string, req?: ExportTransactionDataRequest): Promise { return new Promise((resolve, reject) => { services.getExportedUserData(fileType, req).then(response => { if (response && response.headers) { const contentType = response.headers['content-type']?.toString() || ''; if (fileType === 'csv' && !KnownFileType.CSV.isSameType(contentType)) { reject({ message: 'Unable to retrieve exported user data' }); return; } else if (fileType === 'tsv' && !KnownFileType.TSV.isSameType(contentType)) { reject({ message: 'Unable to retrieve exported user data' }); return; } } const blob = new Blob([response.data], { type: response.headers['content-type'] }); resolve(blob); }).catch(error => { logger.error('failed to retrieve user statistics data', error); if (error.response && KnownFileType.TXT.isSameType(error.response.headers['content-type']) && error.response && error.response.data) { reject({ message: 'error.' + error.response.data }); } else if (!error.processed) { reject({ message: 'Unable to retrieve exported user data' }); } else { reject(error); } }); }); } function getUserAvatarUrl(userInfoOrAvatarUrl: UserBasicInfo | string | null, disableBrowserCache: boolean | string): string | null { let avatarUrl = ''; if (isObject(userInfoOrAvatarUrl)) { avatarUrl = userInfoOrAvatarUrl.avatar; } else if (isString(userInfoOrAvatarUrl)) { avatarUrl = userInfoOrAvatarUrl; } if (!avatarUrl) { return null; } return services.getInternalAvatarUrlWithToken(avatarUrl, disableBrowserCache); } return { // states currentUserBasicInfo, // computed states currentUserNickname, currentUserAvatar, currentUserDefaultAccountId, currentUserLanguage, currentUserDefaultCurrency, currentUserFirstDayOfWeek, currentUserFiscalYearStart, currentUserCalendarDisplayType, currentUserDateDisplayType, currentUserLongDateFormat, currentUserShortDateFormat, currentUserLongTimeFormat, currentUserShortTimeFormat, currentUserFiscalYearFormat, currentUserCurrencyDisplayType, currentUserNumeralSystem, currentUserDecimalSeparator, currentUserDigitGroupingSymbol, currentUserDigitGrouping, currentUserCoordinateDisplayType, currentUserExpenseAmountColor, currentUserIncomeAmountColor, // functions generateNewUserModel, storeUserBasicInfo, resetUserBasicInfo, getCurrentUserProfile, updateUserTransactionEditScope, updateUserAvatar, removeUserAvatar, getUserApplicationCloudSettings, fullUpdateUserApplicationCloudSettings, disableUserApplicationCloudSettings, getUserDataStatistics, getExportedUserData, getUserAvatarUrl }; });