fix bug sms
This commit is contained in:
1 parent
880ac58042
commit
c6d732ff10
2 files changed
+37
No files matched your search
@@ -25,6 +25,7 @@ export default function CustomerLoginForm({ initialStep = 'mobile' }: { initialS
|
||||
const [step, setStep] = useState<Step>(() => initialStep === 'verify' && normalizePhone(readLoginMobile()) ? 'verify' : 'mobile')
|
||||
const [code, setCode] = useState('')
|
||||
const [error, setError] = useState('')
|
||||
const [notice, setNotice] = useState('')
|
||||
const [busy, setBusy] = useState(false)
|
||||
const [options, setOptions] = useState<LoginOption[]>([])
|
||||
const [recoveryMobile, setRecoveryMobile] = useState('')
|
||||
@@ -74,6 +75,7 @@ export default function CustomerLoginForm({ initialStep = 'mobile' }: { initialS
|
||||
if (!normalized) { setError('شماره موبایل معتبر وارد کنید.'); return }
|
||||
await run(async () => {
|
||||
setRecoveryMobile('')
|
||||
setNotice('')
|
||||
let response
|
||||
try {
|
||||
response = await axios.post(process.env.NEXT_PUBLIC_API_URL + '/auth/login/mobile/', { mobile: normalized }, { timeout: 30000 })
|
||||
@@ -91,6 +93,9 @@ export default function CustomerLoginForm({ initialStep = 'mobile' }: { initialS
|
||||
setCode('')
|
||||
setOptions([])
|
||||
setStep('verify') // Never depend on storage or route navigation after SMS.
|
||||
if (response.data?.result?.delivery_status === 'unconfirmed') {
|
||||
setNotice('وضعیت ارسال پیامک تأیید نشد. اگر کد را دریافت کردهاید، آن را وارد کنید؛ در غیر این صورت پس از پایان شمارش دوباره درخواست دهید.')
|
||||
}
|
||||
const wait = Number(response.data?.result?.retry_after || 60)
|
||||
setNow(Date.now())
|
||||
setResendAt(Date.now() + (Number.isFinite(wait) ? Math.min(Math.max(wait, 1), 3600) : 60) * 1000)
|
||||
@@ -125,6 +130,7 @@ export default function CustomerLoginForm({ initialStep = 'mobile' }: { initialS
|
||||
setCode('')
|
||||
setOptions([])
|
||||
setError('')
|
||||
setNotice('')
|
||||
}
|
||||
return <div className="mx-auto w-full sm:w-[30rem]" dir="rtl">
|
||||
<form onSubmit={step === 'mobile' ? sendCode : verify} className="flex flex-col gap-y-3 px-8" aria-busy={busy}>
|
||||
@@ -153,6 +159,7 @@ export default function CustomerLoginForm({ initialStep = 'mobile' }: { initialS
|
||||
<button type="button" disabled={busy} onClick={changeMobile} className="underline disabled:opacity-50">تغییر شماره</button>
|
||||
</>}
|
||||
{remaining > 0 && <p role="status">ارسال دوبارهٔ کد پس از {remaining} ثانیه امکانپذیر است.</p>}
|
||||
{notice && <p role="status" className="bg-amber-50 rounded p-2">{notice}</p>}
|
||||
{error && <p role="alert" className="text-red-700 bg-red-100 rounded p-2">{error}</p>}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -224,6 +224,36 @@ function customerForm(h, props = {}) {
|
||||
const customerOption = name => ({ uuid: name, cuser_role: { sys_ws: { name }, role_type: { role_name_en: 'workspace_customer' } } });
|
||||
const settle = () => new Promise(resolve => setImmediate(resolve));
|
||||
|
||||
test('unconfirmed SMS reply opens OTP and the received code completes login', async () => {
|
||||
const h = harness(); const form = customerForm(h); let sends = 0;
|
||||
h.axios.defaults.adapter = config => {
|
||||
if (config.url.endsWith('/auth/login/mobile/')) {
|
||||
sends++;
|
||||
return Promise.resolve(response(config, { result: { mobile: 9123456789, retry_after: 60, delivery_status: 'unconfirmed' } }, 202));
|
||||
}
|
||||
if (config.url.endsWith('/auth/login/mobile/verify/')) {
|
||||
assert.equal(JSON.parse(config.data).opt, '123456');
|
||||
return Promise.resolve(response(config, [customerOption('customer-panel')]));
|
||||
}
|
||||
return Promise.resolve(response(config, { access: 'access.customer', refresh: 'refresh.customer' }));
|
||||
};
|
||||
form.input('09123456789'); await form.submit();
|
||||
assert.equal(elements(form.render(), item => item.props?.autoComplete === 'one-time-code').length, 1);
|
||||
assert.ok(textContent(form.render()).includes('وضعیت ارسال پیامک تأیید نشد'));
|
||||
assert.equal(elements(form.render(), item => item.props?.role === 'alert').length, 0);
|
||||
form.input('123456'); await form.submit();
|
||||
assert.equal(sends, 1); assert.equal(h.auth.getAccessToken(), 'access.customer');
|
||||
assert.deepEqual(h.redirects, ['/shop']);
|
||||
});
|
||||
test('explicit SMS rejection retains the real error and does not open OTP', async () => {
|
||||
const h = harness(); const form = customerForm(h);
|
||||
h.axios.defaults.adapter = config => Promise.reject(failure(config, 503, { detail: 'ارسال پیامک انجام نشد. لطفاً کمی بعد دوباره تلاش کنید.' }));
|
||||
form.input('09123456789'); await form.submit();
|
||||
assert.ok(textContent(form.render()).includes('ارسال پیامک انجام نشد'));
|
||||
assert.equal(elements(form.render(), item => item.props?.autoComplete === 'one-time-code').length, 0);
|
||||
assert.equal(h.auth.getAccessToken(), null);
|
||||
});
|
||||
|
||||
test('SMS success displays OTP in the same page even when sessionStorage is blocked', async () => {
|
||||
const h = harness(); const form = customerForm(h);
|
||||
h.window.sessionStorage.setItem = () => { throw new Error('Storage denied'); };
|
||||
|
||||
Reference in new issue
Block a user