fix(register): hide or require referral from settings like other apps

Also keep exact trade grams from rial and poll colleague wait every 10s.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-09 21:03:32 +03:30
co-authored by Cursor
parent 0f6d8b37f4
commit c2f6f9d226
6 changed files with 132 additions and 19 deletions
+3 -1
View File
@@ -30,6 +30,8 @@
class=""
@change="handlerChange"
@input="handlerChange"
@blur="emits('blur', $event)"
@focus="emits('focus', $event)"
/>
</div>
</template>
@@ -67,7 +69,7 @@ const addonTextColor = computed(() => props.addonTextColor)
const props = withDefaults(defineProps<Prop>(), {
isPassword: false
})
const emits = defineEmits(['update:value', 'onchange'])
const emits = defineEmits(['update:value', 'onchange', 'blur', 'focus'])
const localValue = computed({
set(value) {
+1 -1
View File
@@ -9,7 +9,7 @@ import { getToken } from '@/utils'
export const colleagueOrderWaiting = ref(false)
const CLIENT_POLL_MS = 5000
const CLIENT_POLL_MS = 10000
const MAX_WAIT_MS = 15 * 60 * 1000
const STREAM_EVENT = 'colleague-order'
+12
View File
@@ -99,6 +99,16 @@ export const useSettingsStore = defineStore('settings', () => {
const metalTypeLabel = computed(() => resolveMetalTypeLabel(metalTypeSettingValue.value))
const meltedGoldLabel = computed(() => resolveMeltedGoldLabel(metalTypeSettingValue.value))
const tradeWeightUnit = computed(() => resolveTradeWeightUnit(getSettingByKey('unit')))
const isReferralFieldVisible = computed(() => {
if (!settings.value?.some((s) => s?.key === 'referral_show')) return true
return isSettingTruthy('referral_show')
})
const isReferralRequired = computed(() => {
if (!isReferralFieldVisible.value) return false
const value = String(getSettingByKey('referral_id') ?? '').trim().toLowerCase()
return value === 'required' || value === 'true' || value === '1' || value === 'yes'
})
return {
settings,
@@ -108,6 +118,8 @@ export const useSettingsStore = defineStore('settings', () => {
mergeSettings,
getSettingByKey,
isSettingTruthy,
isReferralRequired,
isReferralFieldVisible,
metalTypeSettingValue,
metalTypeLabel,
meltedGoldLabel,
+52 -6
View File
@@ -25,9 +25,12 @@ export const TRADE_GRAM_STORAGE_DECIMALS = 10
/** حداکثر اعشار نمایش به کاربر در اپ */
export const TRADE_GRAM_DISPLAY_DECIMALS = 8
/** اعشار فیلد گرم وقتی از ریال تبدیل می‌شود (فقط نمایش همان فیلد) */
/** اعشار فیلد گرم وقتی از ریال تبدیل می‌شود (فقط نمایش همان فیلد؛ مقدار دقیق جداست) */
export const TRADE_GRAM_INPUT_DECIMALS = 3
/** حداکثر اعشاری که کاربر می‌تواند در فیلد گرم تایپ کند */
export const TRADE_GRAM_TYPING_DECIMALS = 6
/** زیر این مقدار (گرم)، معادل گرم در فیلد ورودی نشان داده نمی‌شود */
export const TRADE_GRAM_MIN_DISPLAY_GRAMS = 0.0001
@@ -65,7 +68,7 @@ export function formatTradeGramInputValue(grams?: number | null): string | undef
return value.toFixed(TRADE_GRAM_INPUT_DECIMALS)
}
/** متن اینپوت گرم — فقط نمایش سه‌رقمی؛ منبع حقیقت همان گرم دقیق است */
/** متن اینپوت گرم وقتی مقدار از ریال آمده — فقط نمایش سه‌رقمی؛ منبع حقیقت همان گرم دقیق است */
export function tradeGramInputDisplay(exactGrams?: number | string | null): string {
if (exactGrams === undefined || exactGrams === null || exactGrams === '') return ''
const n = Number(exactGrams)
@@ -73,6 +76,43 @@ export function tradeGramInputDisplay(exactGrams?: number | string | null): stri
return formatTradeGramInputValue(n) ?? ''
}
/** متن اینپوت گرم وقتی خود کاربر وزن زده — تا ۶ رقم، بدون پد اجباری */
export function tradeGramTypedDisplay(exactGrams?: number | string | null): string {
if (exactGrams === undefined || exactGrams === null || exactGrams === '') return ''
const n = Number(exactGrams)
if (!Number.isFinite(n) || n <= 0) return ''
return trimTrailingDecimalZeros(n.toFixed(TRADE_GRAM_TYPING_DECIMALS))
}
export function tradeGramFieldText(
exactGrams: number | string | null | undefined,
inputLock: TradeInputLock,
draft: string | null,
): string {
if (draft !== null) return draft
if (inputLock === 'rial') return tradeGramInputDisplay(exactGrams)
return tradeGramTypedDisplay(exactGrams)
}
/** هنگام تایپ در فیلد گرم: حداکثر شش رقم اعشار؛ نقطهٔ انتهایی برای «۱۲.» نگه داشته می‌شود */
export function sanitizeTradeGramTypingText(raw: unknown): string {
const text = String(raw ?? '')
if (text === '') return ''
const firstDot = text.indexOf('.')
if (firstDot === -1) return text
const intPart = text.slice(0, firstDot)
const decRaw = text.slice(firstDot + 1).replace(/\./g, '')
if (decRaw === '') return `${intPart}.`
return `${intPart}.${decRaw.slice(0, TRADE_GRAM_TYPING_DECIMALS)}`
}
/** متن شروع ویرایش وقتی فیلد از روی ریال پر شده (۱.۰۰۰ → ۱) */
export function tradeGramInputEditText(exactGrams?: number | string | null): string {
const shown = tradeGramInputDisplay(exactGrams)
if (!shown) return ''
return shown.replace(/\.?0+$/, '')
}
/** گرم دقیق از درصد کیف — بدون رند نمایشی اینپوت */
export function exactGoldFromWalletPercent(balance: number, percent: number): number {
if (!(Number(percent) > 0) || !(Number(balance) > 0)) return 0
@@ -88,15 +128,21 @@ export function goldFromGramInputDisplay(
exactGrams?: number | string | null
): number | undefined {
if (raw === '' || raw == null) return undefined
const text = String(raw).trim()
if (text === '') return undefined
const typed = Number(text)
const text = sanitizeTradeGramTypingText(raw).trim()
if (text === '' || text === '.') return undefined
const forNumber = text.endsWith('.') ? text.slice(0, -1) : text
if (forNumber === '') return undefined
const typed = Number(forNumber)
if (!Number.isFinite(typed) || typed <= 0) return undefined
const exact = Number(exactGrams)
if (Number.isFinite(exact) && exact > 0) {
const shown = formatTradeGramInputValue(exact)
if (shown != null && text === shown) {
const typedShown = tradeGramTypedDisplay(exact)
if (
(shown != null && (text === shown || text === shown.replace(/\.?0+$/, ''))) ||
text === typedShown
) {
return normalizeOrderGoldAmount(exact)
}
}
+33 -4
View File
@@ -84,7 +84,7 @@
<BasicInput v-model:value="goldValueInput" :addon-before="weightUnit" :addon-bg-color="colors.primary"
addon-text-color="white"
:place-holder="amountFieldLabel"
size="large" type="text" inputmode="decimal" />
size="large" type="text" inputmode="decimal" @focus="startGramDraft" @blur="commitGramDraft" />
</a-form-item>
<div v-if="cashValidationMessage" class="text-red-700 text-xs font-bold mt-2">
{{ cashValidationMessage }}
@@ -289,7 +289,10 @@ import {
calcTradeTargetCash,
buildTradeConfirmBreakdown,
formatTradeGramDisplay,
tradeGramInputDisplay,
tradeGramFieldText,
tradeGramTypedDisplay,
sanitizeTradeGramTypingText,
tradeGramInputEditText,
exactGoldFromWalletPercent,
goldFromGramInputDisplay,
loadServiceFeeFromSettings,
@@ -441,13 +444,36 @@ const displayTradeGoldAmount = computed(() =>
formatTradeGramDisplay(orderGoldAmount.value)
)
const gramInputDraft = ref<string | null>(null)
function commitGramDraft() {
gramInputDraft.value = null
}
function startGramDraft() {
if (gramInputDraft.value !== null) return
gramInputDraft.value = inputLock.value === 'rial'
? tradeGramInputEditText(form.value.goldValue)
: tradeGramTypedDisplay(form.value.goldValue)
}
const goldValueInput = computed({
get() {
const display = tradeGramInputDisplay(form.value.goldValue)
const display = tradeGramFieldText(form.value.goldValue, inputLock.value, gramInputDraft.value)
return display === '' ? undefined : display
},
set(raw: string | number | null | undefined) {
const next = goldFromGramInputDisplay(raw, form.value.goldValue)
if (raw === '' || raw == null) {
gramInputDraft.value = ''
form.value.goldValue = undefined
form.value.goldCash = undefined
form.value.percentWallet = 0
inputLock.value = null
return
}
const text = sanitizeTradeGramTypingText(raw)
gramInputDraft.value = text
const next = goldFromGramInputDisplay(text, form.value.goldValue)
form.value.goldValue = next
if (next == null) {
form.value.goldCash = undefined
@@ -645,6 +671,7 @@ onMounted(() => {
})
function percentChange(val: number) {
commitGramDraft()
if (val !== 0) {
if (isBuy.value) {
form.value.goldCash = unitCashCalculator.value * val
@@ -711,6 +738,7 @@ function calculateCash(val: number) {
}
function calculateGold(val: number) {
commitGramDraft()
inputLock.value = 'rial'
const unit = unitPrice.value
if (!unit || Number.isNaN(unit)) return
@@ -748,6 +776,7 @@ function setIsBuy(val: boolean) {
form.value.goldCash = undefined
form.value.percentWallet = 0
inputLock.value = null
commitGramDraft()
// console.log(bganim.value.classList)
// bganim?.value?.classList.add(val?'right':'left')
// bganim?.value?.style.transform = `translateX(${val ? '0' : '-100'});`
+31 -7
View File
@@ -18,8 +18,18 @@
<!-- <BasicInput v-model:value="userFormState.password" size="large" place-holder="کلمه عبور"/>-->
<AInputPassword v-model:value="userFormState.password" place-holder="کلمه عبور" inputmode="decimal"/>
</a-form-item>
<a-form-item class="home_appear_fade_in_down" label="کد معرف" name="referral_id">
<BasicInput :disabled="disableForm" v-model:value="userFormState.referral_id" place-holder="کد معرف"/>
<a-form-item
v-if="settingsStore.loaded && settingsStore.isReferralFieldVisible"
:rules="referralIdRules"
class="home_appear_fade_in_down"
:label="referralIdPlaceholder"
name="referral_id"
>
<BasicInput
:disabled="disableForm"
v-model:value="userFormState.referral_id"
:place-holder="referralIdPlaceholder"
/>
</a-form-item>
<!-- <a-form-item v-if="URLUserType() === 'customer'" :rules="[required()]" class="home_appear_fade_in_down"
label="نام فروشگاه" name="shop_name">
@@ -121,7 +131,7 @@ import type { User } from '@/models/login'
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import { loading, URLUserType } from '@/utils'
import { onMounted, reactive, ref } from 'vue'
import { computed, onMounted, reactive, ref } from 'vue'
import type { FormInstance } from 'ant-design-vue'
import { message } from 'ant-design-vue'
import registerDelayImage from '@/assets/img/registerDelay.svg'
@@ -129,8 +139,17 @@ import DialogVantOneButton from '@/components/DialogVantOneButton.vue'
import { registerCustomer } from '@/api/login'
import router from '@/router'
import logo from "@/assets/img/logo_full_.png";
import { useSettingsStore } from '@/store/settingsStore'
const settingsStore = useSettingsStore()
const referralIdRules = computed(() =>
settingsStore.isReferralRequired ? [required('کد معرف')] : [],
)
const referralIdPlaceholder = computed(() =>
settingsStore.isReferralRequired ? 'کد معرف' : 'کد معرف (اختیاری)',
)
// const stepTwoVerify = ref<boolean>(false)
const registeredInfo = ref<boolean>(false)
@@ -148,13 +167,14 @@ async function handleOnComplete(value: string) {
userFormState.token = value
registerAccount()
}*/
onMounted(() => {
onMounted(async () => {
if (!settingsStore.loaded) {
await settingsStore.fetchSettings()
}
if (router.currentRoute.value.query.id){
userFormState.referral_id = router.currentRoute.value.query.id
disableForm.value=true
}
})
function registerAccount() {
@@ -166,7 +186,11 @@ function registerAccount() {
// if (!stepTwoVerify.value) {
URLUserType() === 'single' ? userFormState.type = 2 : userFormState.type = 1
// console.log(userFormState)
if (!userFormState.referral_id || userFormState.referral_id === '') delete userFormState.referral_id
if (!settingsStore.isReferralFieldVisible && !disableForm.value) {
delete userFormState.referral_id
} else if (!userFormState.referral_id || userFormState.referral_id === '') {
delete userFormState.referral_id
}
const { id } = await registerCustomer(userFormState)
registeredInfo.value = true
// console.log(registeredInfo.value)