update empty string to null

This commit is contained in:
2025-07-28 18:17:52 +03:00
parent 6d71c60550
commit 462ed2b671
33 changed files with 369 additions and 242 deletions

View File

@@ -192,12 +192,10 @@
<script setup lang="ts">
import { ref, computed } from 'vue'
import type { AxiosError } from 'axios'
import { useQuasar } from 'quasar'
import { useI18n } from "vue-i18n"
import { QInput } from 'quasar'
import { useAuthStore } from 'stores/auth'
const $q = useQuasar()
const { t } = useI18n()
const authStore = useAuthStore()
@@ -231,39 +229,22 @@
})
const stepActions: Record<Step, () => Promise<void>> = {
1: async () => {
await authStore.getCodeCurrentEmail()
},
2: async () => {
await authStore.confirmCurrentEmailCode(code.value)
console.log(code.value)
},
3: async () => {
await authStore.getCodeNewEmail(code.value, newLogin.value)
},
4: async () => {
await authStore.confirmNewEmailCode(code.value, newCode.value, newLogin.value,)
},
5: async () => {
await authStore.setNewEmailPassword(code.value, newCode.value, newLogin.value, password.value)
await authStore.loginWithCredentials(newLogin.value, password.value)
}
}
const handleError = (err: AxiosError) => {
const error = err as AxiosError<{ error?: { message?: string } }>
const message = error.response?.data?.error?.message || t('unknown_error')
$q.notify({
message: `${t('error')}: ${message}`,
type: 'negative',
position: 'bottom',
timeout: 2500
})
if (step.value > 1) {
code.value = ''
password.value = ''
1: async () => {
await authStore.getCodeCurrentEmail()
},
2: async () => {
await authStore.confirmCurrentEmailCode(code.value)
console.log(code.value)
},
3: async () => {
await authStore.getCodeNewEmail(code.value, newLogin.value)
},
4: async () => {
await authStore.confirmNewEmailCode(code.value, newCode.value, newLogin.value,)
},
5: async () => {
await authStore.setNewEmailPassword(code.value, newCode.value, newLogin.value, password.value)
await authStore.loginWithCredentials(newLogin.value, password.value)
}
}
@@ -276,7 +257,7 @@
showSuccessOverlay.value = true
}
} catch (error) {
handleError(error as AxiosError)
console.error(error as AxiosError)
}
}

View File

@@ -1,7 +1,7 @@
<template>
<pn-page-card>
<template #title>
{{$t('login__register')}}
{{$t('login__register_title')}}
</template>
<pn-scroll-list>
<account-helper :type :email/>

91
src/pages/ChatPage.vue Normal file
View File

@@ -0,0 +1,91 @@
<template>
<pn-page-card>
<template #title>
<pn-account-block-name/>
<q-btn
@click="logout()"
flat
round
icon="mdi-logout"
/>
</template>
<pn-scroll-list>
<q-list separator>
<q-item
v-for="item in displayItems"
:key="item.id"
@click="goTo(item.pathName)"
clickable
v-ripple
>
<q-item-section avatar>
<q-avatar
:icon="item.icon"
:color="item.iconColor ? item.iconColor: 'brand'"
text-color="white"
rounded
font-size ="26px"
/>
</q-item-section>
<q-item-section>
<q-item-label>
{{ $t(item.name) }}
</q-item-label>
<q-item-label class="text-caption" v-if="$te(item.description)">
{{ $t(item.description) }}
</q-item-label>
</q-item-section>
</q-item>
</q-list>
</pn-scroll-list>
</pn-page-card>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useRouter } from 'vue-router'
import { useAuthStore } from 'stores/auth'
const router = useRouter()
const authStore = useAuthStore()
interface ItemList {
id: number
name: string
description?: string
icon: string
iconColor?: string
pathName: string
display?: boolean
}
const items = computed(() => ([
{ id: 1, name: 'account__subscribe', description: 'account__subscribe_description', icon: 'mdi-crown-circle-outline', iconColor: 'orange', pathName: 'subscribe' },
{ id: 2, name: 'account__auth_change_method', description: 'account__auth_change_method_description', icon: 'mdi-account-sync-outline', iconColor: 'primary', pathName: 'change_account_auth_method', display: !authStore.customer?.email },
{ id: 3, name: 'account__auth_change_password', description: 'account__auth_change_password_description', icon: 'mdi-account-key-outline', iconColor: 'primary', pathName: 'change_account_password', display: !!authStore.customer?.email },
{ id: 4, name: 'account__auth_change_account', description: 'account__auth_change_account_description', icon: 'mdi-account-switch-outline', iconColor: 'primary', pathName: 'change_account_email', display: !!authStore.customer?.email },
{ id: 5, name: 'account__company_data', icon: 'mdi-account-group-outline', description: 'account__company_data_description', pathName: 'your_company' },
{ id: 6, name: 'account__settings', icon: 'mdi-cog-outline', description: 'account__settings_description', iconColor: 'info', pathName: 'settings' },
{ id: 7, name: 'account__support', icon: 'mdi-lifebuoy', description: 'account__support_description', iconColor: 'info', pathName: 'support' },
{ id: 9, name: 'account__terms_of_use', icon: 'mdi-book-open-variant-outline', description: '', iconColor: 'grey', pathName: 'terms' },
{ id: 10, name: 'account__privacy', icon: 'mdi-lock-outline', description: '', iconColor: 'grey', pathName: 'privacy' }
]))
const displayItems = computed(() => (
items.value.filter((item: ItemList) => !('display' in item) || item.display === true)
))
async function goTo (path: string) {
await router.push({ name: path })
}
async function logout () {
await authStore.logout()
await router.push({ name: 'login' })
}
</script>
<style lang="scss">
</style>

View File

@@ -8,7 +8,7 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { reactive } from 'vue'
import { useRouter } from 'vue-router'
import companyBlock from 'components/companyBlock.vue'
import { useCompaniesStore } from 'stores/companies'
@@ -17,18 +17,10 @@
const router = useRouter()
const companiesStore = useCompaniesStore()
const newCompany = ref(<CompanyParams>{
name: '',
logo: '',
description: '',
site: '',
address: '',
phone: '',
email: ''
})
const newCompany = reactive<CompanyParams>({} as CompanyParams)
async function addCompany () {
await companiesStore.add(newCompany.value)
async function addCompany(companyData: CompanyParams) {
await companiesStore.add(companyData)
router.go(-1)
}

View File

@@ -1,12 +1,12 @@
<template>
<company-block
v-if="companyMod"
v-model="companyMod"
v-if="company"
v-model="company"
title="company_edit__title_card"
btnText="company_edit__btn"
@update="updateCompany"
>
<template #myCompany v-if="companyMod.is_own">
<template #myCompany v-if="company.is_own">
<div class="q-mb-md flex w100 justify-center">
<div class="flex items-center text-amber-10">
<q-icon name="star" class="q-pr-xs"/>
@@ -32,24 +32,27 @@
const route = useRoute()
const companiesStore = useCompaniesStore()
const companyMod = ref<CompanyParams | null>(null)
const company = ref<CompanyParams | null>(null)
const companyId = computed(() => parseIntString(route.params.companyId))
if (companiesStore.isInit) {
companyMod.value = companyId.value
? { ...companiesStore.companyById(companyId.value) } as CompanyParams
: null
function initCompany() {
if (companiesStore.isInit && companyId.value) {
const foundCompany = companiesStore.companyById(companyId.value)
if (foundCompany) {
company.value = foundCompany as CompanyParams
}
}
}
if (companiesStore.isInit) initCompany()
watch(() => companiesStore.isInit, (isInit) => {
if (isInit && companyId.value && !companyMod.value) {
companyMod.value = { ...companiesStore.companyById(companyId.value) as CompanyParams }
}
if (isInit) initCompany()
})
async function updateCompany () {
if (companyId.value && companyMod.value) {
await companiesStore.update(companyId.value, companyMod.value)
async function updateCompany(companyData: CompanyParams) {
if (companyId.value) {
await companiesStore.update(companyId.value, companyData)
router.go(-1)
}
}

View File

@@ -1,18 +1,23 @@
<template>
<q-page class="flex column items-center justify-between">
<div :style="{ height: `${blockHeight}px` }" />
<q-page
class="q-ma-none w100"
>
<q-scroll-area
style="height: 100vh"
>
<div class="flex items-center justify-center" style="height: 100vh">
<q-card
id="login_block"
flat
class="flex column items-center w80 justify-between q-py-md login-card "
class="flex column no-wrap items-center justify-between q-px-xl q-py-md login-card"
style="max-width: 400px;"
>
<login-logo
class="col-grow q-pa-md"
<base-logo
class="col-grow q-pa-lg"
:style="{ alignItems: 'flex-end' }"
/>
<div class="q-ma-md flex column input-login">
<div class="flex column w100">
<q-input
v-model="login"
autofocus
@@ -67,29 +72,30 @@
</q-btn>
</div>
</div>
<q-btn
@click="sendAuth()"
color="primary"
:disabled="!acceptTermsOfUse || !isEmailValid || !isPasswordValid"
>
{{$t('login__sign_in')}}
</q-btn>
<div class="q-pt-lg">
<q-btn
@click="sendAuth()"
color="primary"
class="w100 q-my-md"
:disabled="!isEmailValid || !isPasswordValid"
>
{{$t('login__sign_in')}}
</q-btn>
<q-btn
flat
sm
no-caps
class="q-my-md"
color="primary"
@click="createAccount"
>
{{$t('login__register')}}
</q-btn>
</div>
<div
v-if="isTelegramApp"
id="alt_login"
class="w80 q-flex column items-center q-pt-md"
class="flex w100 column items-center "
>
<div
class="orline w100 text-grey"
@@ -101,7 +107,7 @@
sm
no-caps
color="primary"
:disabled="!acceptTermsOfUse"
class="q-my-md"
@click="handleTelegramLogin"
>
<div class="flex items-center text-blue">
@@ -122,45 +128,19 @@
</q-btn>
</div>
</q-card>
<div
id="term-of-use"
class="q-pb-md text-white flex justify-center row text-caption"
ref="bottomBlock"
>
<q-resize-observer @resize="syncHeights" />
<q-checkbox
v-model="acceptTermsOfUse"
checked-icon="task_alt"
unchecked-icon="highlight_off"
:color="acceptTermsOfUse ? 'brand' : 'red'"
dense
keep-color
size="sm"
/>
<span class="q-px-xs">
{{ $t('login__accept_terms_of_use') + ' ' }}
</span>
<span
@click="router.push('terms-of-use')"
style="text-decoration: underline;"
>
{{ $t('login__terms_of_use') }}
</span>
</div>
</q-scroll-area>
</q-page>
</template>
<script setup lang="ts">
import { ref, computed, inject, onUnmounted } from 'vue'
import { useRouter } from 'vue-router'
import loginLogo from 'components/login-page/loginLogo.vue'
import baseLogo from 'components/BaseLogo.vue'
import { useI18n } from "vue-i18n"
import { useAuthStore } from 'stores/auth'
import type { WebApp } from '@twa-dev/types'
import { QInput } from 'quasar'
import { useNotify, type ServerError } from 'composables/useNotify'
const { notifyError } = useNotify()
type ValidationRule = (val: string) => boolean | string
@@ -174,10 +154,6 @@
const login = ref<string>('')
const password = ref<string>('')
const isPwd = ref<boolean>(true)
const acceptTermsOfUse = ref<boolean>(true)
const bottomBlock = ref<HTMLDivElement | null>(null)
const blockHeight = ref<number>(0)
const emailInput = ref<InstanceType<typeof QInput>>()
const passwordInput = ref<InstanceType<typeof QInput>>()
@@ -223,7 +199,7 @@
async function sendAuth() {
try { void await authStore.loginWithCredentials(login.value, password.value) }
catch (error) {
notifyError(error as ServerError)
console.error(error)
}
await router.push({ name: 'projects' })
}
@@ -251,12 +227,6 @@
await router.push({ name: 'projects' })
}
function syncHeights() {
if (bottomBlock.value) {
blockHeight.value = bottomBlock.value.offsetHeight
}
}
onUnmounted(() => {
Object.values(validateTimerId.value).forEach(timer => timer && clearTimeout(timer))
})
@@ -264,16 +234,6 @@
</script>
<style scoped>
.maxh15 {
max-height: calc(100Vh *0.15);
}
.input-login {
width: calc(100% * 0.8);
max-width: 300px;
}
.login-card {
opacity: 0.9 !important;
border-radius: var(--top-raduis);

View File

@@ -10,13 +10,12 @@
<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useRouter } from 'vue-router'
import projectBlock from 'components/projectBlock.vue'
import { useProjectsStore } from 'stores/projects'
import type { ProjectParams } from 'types/Project'
const router = useRouter()
const route = useRoute()
const projectsStore = useProjectsStore()
const projectId = computed(() => projectsStore.currentProjectId)

View File

@@ -1,7 +1,7 @@
<template>
<user-block
v-if="userMod"
v-model="userMod"
v-if="user"
v-model="user"
title="user_edit__title_card"
btnText="user_edit__btn"
@update="updateUser"
@@ -20,24 +20,25 @@
const route = useRoute()
const usersStore = useUsersStore()
const userMod = ref<User | null>(null)
const user = ref<User | null>(null)
const userId = computed(() => parseIntString(route.params.userId))
if (usersStore.isInit) {
userMod.value = userId.value
? { ...usersStore.userById(userId.value) } as User
: null
function initUser() {
if (usersStore.isInit && userId.value) {
const foundUser = usersStore.userById(userId.value)
if (foundUser) {
user.value = { ...foundUser } as User
}
}
}
watch(() => usersStore.isInit, (isInit) => {
if (isInit && userId.value && !userMod.value) {
userMod.value = { ...usersStore.userById(userId.value) as User }
}
})
if (usersStore.isInit) initUser()
async function updateUser () {
if (userId.value && userMod.value) {
await usersStore.update(userId.value, userMod.value)
watch(() => usersStore.isInit, initUser)
async function updateUser (userData: User) {
if (userId.value) {
await usersStore.update(userId.value, userData)
router.go(-1)
}
}