From b094349b8877f6877dcb43da4c59595a666bd482 Mon Sep 17 00:00:00 2001 From: YNWA Fawzy <38886749+Cybrarist@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:16:44 +0400 Subject: [PATCH] Enhancements: - in edit product, show price notification fields only when url is available with message. Took 26 minutes --- app/Filament/Resources/ProductResource.php | 32 ++- .../ProductResource/Pages/EditProduct.php | 58 ++--- app/Helpers/URLHelper.php | 227 +++++++++--------- 3 files changed, 166 insertions(+), 151 deletions(-) diff --git a/app/Filament/Resources/ProductResource.php b/app/Filament/Resources/ProductResource.php index b7bc1a0..4e1b70f 100644 --- a/app/Filament/Resources/ProductResource.php +++ b/app/Filament/Resources/ProductResource.php @@ -66,27 +66,37 @@ public static function form(Form $form): Form ->afterStateUpdated(function ($state) { if ($state) { $url = new URLHelper($state); + if ($url->store) { StoreHelper::is_unique($url); } } }), + Select::make('status') ->options(StatusEnum::class) ->default(StatusEnum::Published) ->preload() ->native(false), - TextInput::make('notify_price') - ->nullable() - ->numeric(), + Forms\Components\Fieldset::make() + ->label('These field is for new store addition') + ->columnSpan(1) + ->hidden(fn ($operation, $get) => $operation == "edit" && ! $get('url')) + ->schema([ + TextInput::make('notify_price') + ->hint('') + ->nullable() + ->numeric(), + + TextInput::make('notify_percentage') + ->nullable() + ->hintIcon("heroicon-o-information-circle", "Get notified when price drops below specified percentage") + ->suffix('%') + ->numeric(), + ]), - TextInput::make('notify_percentage') - ->nullable() - ->hintIcon("heroicon-o-information-circle", "Get notified when price drops below specified percentage") - ->suffix('%') - ->numeric(), Select::make('categories') ->relationship('categories', 'name') @@ -348,10 +358,10 @@ public static function table(Table $table): Table Filter::make('lowest_within') ->form([ - TextInput::make('lowest_within_x') - ->label('Price is lowest in X Days'), + TextInput::make('lowest_within_x') + ->label('Price is lowest in X Days'), - ]) + ]) ->query(function (Builder $query, $data) { if (! $data["lowest_within_x"]) { diff --git a/app/Filament/Resources/ProductResource/Pages/EditProduct.php b/app/Filament/Resources/ProductResource/Pages/EditProduct.php index dee5e27..d4cb155 100644 --- a/app/Filament/Resources/ProductResource/Pages/EditProduct.php +++ b/app/Filament/Resources/ProductResource/Pages/EditProduct.php @@ -10,67 +10,60 @@ use App\Models\ProductStore; use App\Models\Store; use Filament\Actions; +use Filament\Notifications\Notification; use Filament\Resources\Pages\EditRecord; use Illuminate\Support\Arr; use Livewire\Attributes\On; class EditProduct extends EditRecord { - protected static string $resource = ProductResource::class; - protected static ?string $title="Edit Product"; + protected static ?string $title = "Edit Product"; protected function getHeaderActions(): array { - return [ + return [ Actions\DeleteAction::make(), Actions\Action::make('Fetch') ->color('primary') - ->action(fn()=> StoreHelper::fetch_product($this->record)) - ->after(fn ($livewire) => $livewire->dispatch('refresh')) + ->action(fn () => StoreHelper::fetch_product($this->record)) + ->after(fn ($livewire) => $livewire->dispatch('refresh')), ]; } - protected function mutateFormDataBeforeSave(array $data) : array{ - - $extra_data=[ - 'notify_price'=>$data['notify_price'] ?? null, - 'notify_percentage'=>$data['notify_percentage'] ?? null, + protected function mutateFormDataBeforeSave(array $data): array + { + $extra_data = [ + 'notify_price' => $data['notify_price'] ?? null, + 'notify_percentage' => $data['notify_percentage'] ?? null, ]; + if ($data['url']) { + $new_url = new URLHelper($data['url']); - if ($data['url']){ - $new_url=new URLHelper($data['url']); + $extra_data['key'] = $new_url->product_unique_key; + // if product across multi region store has the same id, then user can just add the domain + // and the code will add the other store. - $extra_data['key']=$new_url->product_unique_key; - - //if product across multi region store has the same id, then user can just add the domain - // and the code will add the other store. - - - if (!$new_url->product_unique_key){ - $get_same_store_product= ProductStore::where("product_id", $this->record->id) - ->whereIn("store_id" , Store::where('domain' , 'like' , $new_url->top_host.'%')->pluck("id")->toArray()) + if (! $new_url->product_unique_key) { + $get_same_store_product = ProductStore::where("product_id", $this->record->id) + ->whereIn("store_id", Store::where('domain', 'like', $new_url->top_host.'%')->pluck("id")->toArray()) ->first(); - - $extra_data['key']=$get_same_store_product->key; - } - elseif( !StoreHelper::is_unique($new_url)) + $extra_data['key'] = $get_same_store_product->key; + } elseif (! StoreHelper::is_unique($new_url)) { $this->halt(); + } - StoreTemplate::insert_other_store(domain: $new_url->domain , product_id: $this->record->id, extra_data: $extra_data); - + StoreTemplate::insert_other_store(domain: $new_url->domain, product_id: $this->record->id, extra_data: $extra_data); $this->dispatch('refresh_products_relation'); } - - - return Arr::except($data , ["url"]); + return Arr::except($data, ["url"]); } protected function getFooterWidgets(): array @@ -80,12 +73,11 @@ protected function getFooterWidgets(): array ]; } - #[On('refresh')] - public function refresh_the_form(): void { + public function refresh_the_form(): void + { $this->refreshFormData( $this->record->getFillable() ); } - } diff --git a/app/Helpers/URLHelper.php b/app/Helpers/URLHelper.php index e695aa7..db7604f 100644 --- a/app/Helpers/URLHelper.php +++ b/app/Helpers/URLHelper.php @@ -7,146 +7,150 @@ use Exception; use Filament\Notifications\Notification; use Illuminate\Support\Arr; -use Illuminate\Support\Facades\Context; use Illuminate\Support\Str; -use Illuminate\Support\Stringable; class URLHelper { public string $final_url; + public string $domain; - public string $top_host; - private string $path; - public string $product_unique_key= ""; - public ?Store $store; + public string $top_host; - public function __construct(private string $url) { - try { - //parse the url - $parsed_url=parse_url($url); + private string $path; - $this->domain= Str::of($parsed_url['host'])->lower()->remove(['www.' , 'uae.']); + public string $product_unique_key = ""; + public ?Store $store=null; -// Str::lower(Str::remove("www.",$parsed_url['host'])); + public function __construct(private string $url) + { + try { + // parse the url + $parsed_url = parse_url($url); -// if ($this->domain==="uae.emaxme.com") -// $this->domain=Str::remove("uae.",$parsed_url['host']); + $this->domain = Str::of($parsed_url['host'])->lower()->remove(['www.', 'uae.']); - $this->store=Store::whereDomain($this->domain)->first(); + $this->store = Store::whereDomain($this->domain)->firstOrFail(); - //check the store exists - throw_if(!$this->store , new \Exception("This store doesn't exist in the database, please check the url")); - $remove_ref_if_exists=explode("/ref" , $parsed_url['path'] ?? ""); - $this->path= $remove_ref_if_exists[0] ?? ""; - $this->final_url="https://$this->domain$this->path"; - $this->top_host= explode('.', $parsed_url["host"])[0]; + // check the store exists + $remove_ref_if_exists = explode("/ref", $parsed_url['path'] ?? ""); + $this->path = $remove_ref_if_exists[0] ?? ""; + $this->final_url = "https://$this->domain$this->path"; + $this->top_host = explode('.', $parsed_url["host"])[0]; self::get_key(); - } - catch (Exception $exception){ + } catch (Exception $exception) { Notification::make() ->danger() ->title("Wrong Store") - ->body($exception->getMessage()) + ->body("Couldn't get the store") ->persistent() ->send(); - return ; + return; } } - - - public function get_key() + public function get_key(): void { - $function_to_be_called= "self::get_" . explode("." , $this->domain)[0] ."_key"; - $this->product_unique_key=call_user_func($function_to_be_called); + $function_to_be_called = "self::get_".explode(".", $this->domain)[0]."_key"; + $this->product_unique_key = call_user_func($function_to_be_called); } - //todo move all of the following to the classes as static method - //methods to collect unique products keys - public function get_argos_key(): string + // todo move all of the following to the classes as static method + // methods to collect unique products keys + public function get_argos_key(): string { - return Str::remove("/" , Str::squish( Arr::last(explode("/" , $this->path))) ); + return Str::remove("/", Str::squish(Arr::last(explode("/", $this->path)))); } - public function get_ajio_key(): string { + public function get_ajio_key(): string + { + + $paths = explode("/p/", $this->path); - $paths=explode("/p/" , $this->path); - return (sizeof($paths) ==1 ) ? $paths[0] : $paths[1]; + return (count($paths) == 1) ? $paths[0] : $paths[1]; } - public function get_amazon_key(): string + public function get_amazon_key(): string { - $this->path=Str::replace( "/gp/product/" , "/dp/" , $this->path , false); + $this->path = Str::replace("/gp/product/", "/dp/", $this->path, false); - $dp_temp= explode("/dp/" , $this->path); + $dp_temp = explode("/dp/", $this->path); - if (sizeof($dp_temp)<=1) + if (count($dp_temp) <= 1) { return ""; + } - $temp=$dp_temp[1]; + $temp = $dp_temp[1]; - $check_slashes_after_dp=explode("/" , $temp); - if ($check_slashes_after_dp) - $temp=$check_slashes_after_dp[0]; + $check_slashes_after_dp = explode("/", $temp); + if ($check_slashes_after_dp) { + $temp = $check_slashes_after_dp[0]; + } - return Str::remove("/" ,Str::squish( $temp) ); + return Str::remove("/", Str::squish($temp)); } - public function get_bestbuy_key():string { - $temp=explode("/" , $this->path); + public function get_bestbuy_key(): string + { + $temp = explode("/", $this->path); - //todo if same after finihsing implementing ca then remove. - return match ($this->domain){ - 'bestbuy.com'=>explode("." , Arr::last($temp))[0], - 'bestbuy.ca'=>Arr::last($temp), + // todo if same after finihsing implementing ca then remove. + return match ($this->domain) { + 'bestbuy.com' => explode(".", Arr::last($temp))[0], + 'bestbuy.ca' => Arr::last($temp), }; } - public function get_canadiantire_key(): string { - $paths= explode("/pdp" , $this->path); - $sections=explode("-" , $paths[1]); + public function get_canadiantire_key(): string + { + $paths = explode("/pdp", $this->path); + $sections = explode("-", $paths[1]); - return Str::remove(".html" ,Arr::last($sections)); + return Str::remove(".html", Arr::last($sections)); } - public function get_costco_key(): string { - return match ($this->domain) - { - "costco.com","costco.ca"=>Str::replace(["." , "html"] , "" , explode(".product" , $this->path)[1]), - "costco.com.mx","costco.co.uk","costco.co.kr","costco.com.tw","costco.co.jp","costco.com.au","costco.is"=>explode("/p/" , $this->path)[1], + public function get_costco_key(): string + { + return match ($this->domain) { + "costco.com","costco.ca" => Str::replace([".", "html"], "", explode(".product", $this->path)[1]), + "costco.com.mx","costco.co.uk","costco.co.kr","costco.com.tw","costco.co.jp","costco.com.au","costco.is" => explode("/p/", $this->path)[1], }; } - public function get_currys_key(): string { + public function get_currys_key(): string + { - $paths= explode("/" , $this->path); - $sections=explode("-" , $paths[2]); + $paths = explode("/", $this->path); + $sections = explode("-", $paths[2]); - return Str::remove(".html" ,Arr::last($sections)); + return Str::remove(".html", Arr::last($sections)); } - public function get_diy_id(): string { + public function get_diy_id(): string + { - $this->path=Str::remove(["/departments/","_BQ.prd"] , $this->path); - $is_two_parts=explode("/" , $this->path); + $this->path = Str::remove(["/departments/", "_BQ.prd"], $this->path); + $is_two_parts = explode("/", $this->path); - if (sizeof($is_two_parts) > 2) + if (count($is_two_parts) > 2) { throw new \Exception("wrong url"); - else - return (sizeof($is_two_parts) > 1) ? $is_two_parts[1] : $is_two_parts[0]; + } else { + return (count($is_two_parts) > 1) ? $is_two_parts[1] : $is_two_parts[0]; + } } - public function get_ebay_key(){ - return explode("/itm/" , $this->path)[1]; + public function get_ebay_key() + { + return explode("/itm/", $this->path)[1]; } - public function get_emaxme_key(): string { - return Str::remove(["/",'.html'], $this->path); + public function get_emaxme_key(): string + { + return Str::remove(["/", '.html'], $this->path); } public function get_flipkart_key(): string @@ -154,75 +158,84 @@ public function get_flipkart_key(): string return Str::after($this->path, 'itm'); } - public function get_mediamarkt_key(): string { - $temp=explode("-" , $this->path); - $product_key=explode(".html" , end($temp))[0]; + public function get_mediamarkt_key(): string + { + $temp = explode("-", $this->path); + $product_key = explode(".html", end($temp))[0]; return $product_key; } - public function get_myntra_key(): string { - $temp=explode("/" , $this->path); + public function get_myntra_key(): string + { + $temp = explode("/", $this->path); - $product_key=$temp[sizeof($temp)-2]; + $product_key = $temp[count($temp) - 2]; return $product_key; } - public function get_noon_key(): string { + public function get_noon_key(): string + { - $paths=explode("/" , $this->path); + $paths = explode("/", $this->path); - //update the store for noon, since they use path instead of custom domain per country - $this->store=match (Str::lower(explode("-" , $paths[1])[0])) { - "uae" => Store::whereDomain($this->domain)->whereCurrencyId(Currency::where("code" , "AED")->first()->id)->first(), - "egypt" => Store::whereDomain($this->domain)->whereCurrencyId(Currency::where("code" , "EGP")->first()->id)->first(), - "saudi" => Store::whereDomain($this->domain)->whereCurrencyId(Currency::where("code" , "SAR")->first()->id)->first(), + // update the store for noon, since they use path instead of custom domain per country + $this->store = match (Str::lower(explode("-", $paths[1])[0])) { + "uae" => Store::whereDomain($this->domain)->whereCurrencyId(Currency::where("code", "AED")->first()->id)->first(), + "egypt" => Store::whereDomain($this->domain)->whereCurrencyId(Currency::where("code", "EGP")->first()->id)->first(), + "saudi" => Store::whereDomain($this->domain)->whereCurrencyId(Currency::where("code", "SAR")->first()->id)->first(), }; - return Str::lower($paths[sizeof($paths)-3]); - + return Str::lower($paths[count($paths) - 3]); throw new \Exception("wrong formula"); } + public function get_nykaa_key(): string + { - public function get_nykaa_key(): string { + $paths = explode("/p/", $this->path); - $paths=explode("/p/" , $this->path); - return (sizeof($paths) ==1 ) ? $paths[0] : $paths[1]; + return (count($paths) == 1) ? $paths[0] : $paths[1]; } + public function get_princessauto_key(): string + { + $temp = explode("/product/", $this->path)[1]; - - - public function get_princessauto_key():string { - $temp=explode("/product/" , $this->path)[1]; - return Str::remove("/" ,Str::squish( $temp) ); + return Str::remove("/", Str::squish($temp)); } - public function get_snapdeal_key():string { - $temp=explode("/" , $this->path); + public function get_snapdeal_key(): string + { + $temp = explode("/", $this->path); + return Arr::last($temp); } public function get_target_key() { - if (Str::contains( $this->url,"preselect", true)) - return "A-" . explode("#",explode("preselect=", $this->url)[1])[0]; + if (Str::contains($this->url, "preselect", true)) { + return "A-".explode("#", explode("preselect=", $this->url)[1])[0]; + } + + $paths = explode("/-/", $this->path); - $paths= explode("/-/" , $this->path); return $paths[1]; } + public function get_tatacliq_key() { - $paths= explode("/p-mp" , $this->path); + $paths = explode("/p-mp", $this->path); + return $paths[1]; } - public function get_walmart_key(): string { -// return Str::remove("/" , Str::squish( Arr::last(explode("/" , $this->path))) ); - return explode('/ip/' , $this->path)[1]; + public function get_walmart_key(): string + { + // return Str::remove("/" , Str::squish( Arr::last(explode("/" , $this->path))) ); + return explode('/ip/', $this->path)[1]; } }