redirectIfAlreadyRegistered()) { return $redirect; } if (! $this->couponCodePool->hasAvailable()) { return view('verification.promotion-ended'); } return view('verification.index'); } public function sendOtp(SendOtpRequest $request): RedirectResponse { if ($request->cookie(self::DEVICE_COOKIE_NAME)) { return back()->withErrors(['phone' => 'Siz eýýäm agza bolduňyz.']); } $phone = $request->unmaskedPhone(); $existingCoupon = Coupon::query()->where('phone', $phone)->first(); if ($existingCoupon) { return back()->withErrors(['phone' => 'Bu telefon belgisi eýýäm ulanyldy.'])->withInput(); } if (! $this->couponCodePool->hasAvailable()) { return back()->withErrors(['phone' => CouponPoolExhaustedException::MESSAGE])->withInput(); } if (! $this->otpService->issue($phone)) { return back()->withErrors(['phone' => 'SMS iberilmedi. Soňrak synanyşyň.'])->withInput(); } session()->put('verify_phone', $phone); return redirect()->route('verification.verify.form'); } public function verifyForm(): View|RedirectResponse { if ($redirect = $this->redirectIfAlreadyRegistered()) { return $redirect; } if (! session()->has('verify_phone')) { return redirect()->route('verification.index'); } $phone = session()->get('verify_phone'); if (! $this->couponCodePool->hasAvailable() && ! Coupon::query()->where('phone', $phone)->exists()) { return redirect()->route('verification.index'); } return view('verification.verify', [ 'phone' => session()->get('verify_phone'), ]); } public function resendOtp(Request $request): RedirectResponse { if ($request->cookie(self::DEVICE_COOKIE_NAME)) { return redirect()->route('verification.congratulations'); } $phone = session()->get('verify_phone'); if (! $phone) { return redirect()->route('verification.index'); } if (Coupon::query()->where('phone', $phone)->exists()) { return redirect()->route('verification.congratulations'); } if (! $this->couponCodePool->hasAvailable()) { return redirect()->route('verification.index'); } if (! $this->otpService->issue($phone)) { return back()->withErrors(['otp' => 'SMS iberilmedi. Soňrak synanyşyň.']); } return back()->with('status', 'Täze kod iberildi!'); } public function verifyOtp(VerifyOtpRequest $request): RedirectResponse { $phone = session()->get('verify_phone'); if (! $phone) { return redirect()->route('verification.index'); } $result = $this->otpService->verify($phone, $request->string('otp')->toString()); if ($result === OtpVerificationResult::Expired) { return back()->withErrors(['otp' => 'Kodyň möhleti gutardy.']); } if ($result === OtpVerificationResult::Invalid) { return back()->withErrors(['otp' => 'Nädogry kod.']); } try { $coupon = $this->couponService->findOrCreateForPhone($phone); } catch (CouponPoolExhaustedException) { return back()->withErrors(['otp' => CouponPoolExhaustedException::MESSAGE]); } session()->put('coupon_code', $coupon->code); sendSMS($phone, 'Gutlaýarys! Kupon koduňyz: '.$coupon->code); return redirect() ->route('verification.congratulations') ->withCookie($this->makeDeviceCookie($phone)); } public function congratulations(): View|RedirectResponse { if (! session()->has('coupon_code') && ! request()->cookie(self::DEVICE_COOKIE_NAME)) { return redirect()->route('verification.index'); } $sessionCode = session()->get('coupon_code'); $code = null; if ($sessionCode && Coupon::query()->where('code', $sessionCode)->exists()) { $code = $sessionCode; } elseif ($sessionCode) { session()->forget('coupon_code'); } if (! $code) { $phone = $this->phoneFromDeviceCookie(); if ($phone) { $coupon = Coupon::query()->where('phone', $phone)->first(); if ($coupon) { $code = $coupon->code; session()->put('coupon_code', $code); } } } if (! $code && session()->has('verify_phone')) { $coupon = Coupon::query()->where('phone', session()->get('verify_phone'))->first(); if ($coupon) { $code = $coupon->code; session()->put('coupon_code', $code); } } if (! $code) { return redirect() ->route('verification.index') ->withoutCookie(self::DEVICE_COOKIE_NAME); } return view('verification.congratulations', [ 'code' => $code, ]); } private function redirectIfAlreadyRegistered(): ?RedirectResponse { if (request()->cookie(self::DEVICE_COOKIE_NAME) || session()->has('coupon_code')) { return redirect()->route('verification.congratulations'); } return null; } private function makeDeviceCookie(string $phone): Cookie { return cookie( self::DEVICE_COOKIE_NAME, encrypt($phone), 60 * 24 * 365 * 5, '/', null, null, true, false, 'lax', ); } private function phoneFromDeviceCookie(): ?string { $value = request()->cookie(self::DEVICE_COOKIE_NAME); if (! $value) { return null; } try { $phone = decrypt($value); return is_string($phone) && preg_match('/^6\d{7}$/', $phone) ? $phone : null; } catch (\Throwable) { return null; } } }