user(); $customer = $this->account->customer($user); return view('account.show', [ 'user' => $user, 'customer' => $customer, 'address' => $this->defaultAddress($user), 'regions' => State::where('country_id', $this->storeCountry()->id)->orderBy('name')->get(['id', 'name']), ]); } public function update(string $locale, Request $request): RedirectResponse { $user = $request->user(); $country = $this->storeCountry(); // The address is all-or-nothing: typing any part of it makes the rest // (and the name, which Lunar requires on every address) required. $anyAddressField = implode(',', self::ADDRESS_FIELDS); $data = $request->validate([ 'first_name' => ['nullable', 'string', 'max:255', 'required_with:'.$anyAddressField], 'last_name' => ['nullable', 'string', 'max:255', 'required_with:'.$anyAddressField], 'invoice' => ['boolean'], 'company_name' => ['nullable', 'string', 'max:255', 'required_if_accepted:invoice'], 'tax_identifier' => ['nullable', 'digits:9', 'required_if_accepted:invoice'], 'line_one' => ['nullable', 'string', 'max:255', 'required_with:'.$anyAddressField], 'city' => ['nullable', 'string', 'max:255', 'required_with:'.$anyAddressField], 'postcode' => ['nullable', 'regex:/^\d{3}\s?\d{2}$/', 'required_with:'.$anyAddressField], 'state' => [ 'nullable', 'string', 'required_with:'.$anyAddressField, Rule::exists((new State)->getTable(), 'name')->where('country_id', $country->id), ], 'contact_phone' => ['nullable', 'string', 'max:30'], 'recovery_consent' => ['boolean'], ]); $invoice = $request->boolean('invoice'); $this->account->updateProfile($user, [ 'first_name' => $data['first_name'] ?? null, 'last_name' => $data['last_name'] ?? null, 'company_name' => $invoice ? $data['company_name'] : null, 'tax_identifier' => $invoice ? $data['tax_identifier'] : null, ]); if (filled($data['line_one'] ?? null)) { $addressData = [ ...collect($data)->only(self::ADDRESS_FIELDS)->all(), 'first_name' => $data['first_name'], 'last_name' => $data['last_name'], 'country_id' => $country->id, 'contact_email' => $user->email, 'shipping_default' => true, 'billing_default' => true, ]; $existing = $this->defaultAddress($user); $existing ? $this->account->updateAddress($user, $existing->id, $addressData) : $this->account->createAddress($user, $addressData); } $this->updateRecoveryConsent($user, $request->boolean('recovery_consent')); return redirect()->route('account')->with('status', __('storefront.account.saved')); } /** * "Email me a reminder if I don't finish my order", as a standing * choice — stored on the customer via boboko-core's * CustomerAccountService::setRecoveryConsent(), and applied to the * current cart too, so opting out stops reminders for it right away. */ private function updateRecoveryConsent($user, bool $consent): void { $this->account->setRecoveryConsent($user, $consent); // Only an existing cart; never create one just to record this. $cart = app(CartService::class)->current(); if ($cart && (bool) data_get($cart, 'meta.recovery_consent') !== $consent) { app(CheckoutService::class)->setRecoveryConsent($consent); } } /** * Self-service deletion: opens core's 30-day grace-period erasure request * (which blocks the login right away) and logs out. Logging back in within * the grace period cancels it; see core's docs/privacy.md. */ public function destroy(string $locale, Request $request, PrivacyService $privacy): RedirectResponse { $user = $request->user(); $privacy->requestErasureForUser($user, $user); Auth::logout(); $request->session()->invalidate(); $request->session()->regenerateToken(); return redirect()->route('login')->with('status', __('storefront.account.deletion_requested')); } private function defaultAddress($user) { $addresses = collect($this->account->addresses($user)); return $addresses->firstWhere('shipping_default', true) ?? $addresses->first(); } private function storeCountry(): Country { return Country::where('iso3', self::STORE_COUNTRY_ISO3)->firstOrFail(); } }