diff --git a/resources/lang/en/countries.php b/resources/lang/en/countries.php index 5f905a5..0260dc4 100644 --- a/resources/lang/en/countries.php +++ b/resources/lang/en/countries.php @@ -68,4 +68,22 @@ 'helper' => 'Numeric code (ISO-3166)', ], ], + + 'import' => [ + 'action_label' => 'Import Countries', + 'modal_heading' => 'Import Countries', + 'success_title' => 'Import Countries', + 'success_message' => 'The import countries job has been queued.', + ], + + 'notifications' => [ + 'success' => [ + 'title' => 'Countries Import Completed', + 'message' => 'All countries have been successfully imported and updated.', + ], + 'failed' => [ + 'title' => 'Countries Import Failed', + 'message' => 'Failed to import countries data.', + ], + ], ]; diff --git a/resources/lang/en/posts.php b/resources/lang/en/posts.php index e4f1137..d1c96c6 100644 --- a/resources/lang/en/posts.php +++ b/resources/lang/en/posts.php @@ -75,4 +75,15 @@ 'HR' => 'Croatia', ], ], + + 'notifications' => [ + 'success' => [ + 'title' => 'Posts Import Completed', + 'message' => 'Postal data for :country has been successfully imported.', + ], + 'failed' => [ + 'title' => 'Posts Import Failed', + 'message' => 'Failed to import postal data for :country.', + ], + ], ]; diff --git a/resources/lang/hr/countries.php b/resources/lang/hr/countries.php index 6c64cec..e568c0f 100644 --- a/resources/lang/hr/countries.php +++ b/resources/lang/hr/countries.php @@ -68,4 +68,22 @@ 'helper' => 'Numerička oznaka (ISO-3166)', ], ], + + 'import' => [ + 'action_label' => 'Uvezi države', + 'modal_heading' => 'Uvoz država', + 'success_title' => 'Uvoz država', + 'success_message' => 'Zadatak za uvoz država je dodan u red čekanja.', + ], + + 'notifications' => [ + 'success' => [ + 'title' => 'Uvoz država završen', + 'message' => 'Sve države su uspješno uvežene i ažurirane.', + ], + 'failed' => [ + 'title' => 'Uvoz država neuspješan', + 'message' => 'Neuspješan uvoz podataka država.', + ], + ], ]; diff --git a/resources/lang/hr/posts.php b/resources/lang/hr/posts.php index 15f33ee..a28d748 100644 --- a/resources/lang/hr/posts.php +++ b/resources/lang/hr/posts.php @@ -75,4 +75,15 @@ 'HR' => 'Hrvatska', ], ], + + 'notifications' => [ + 'success' => [ + 'title' => 'Uvoz pošta završen', + 'message' => 'Poštanski podaci za :country su uspješno uveženi.', + ], + 'failed' => [ + 'title' => 'Uvoz pošta neuspješan', + 'message' => 'Neuspješan uvoz poštanskih podataka za :country.', + ], + ], ]; diff --git a/resources/lang/sl/countries.php b/resources/lang/sl/countries.php index 11349cc..90fb45f 100644 --- a/resources/lang/sl/countries.php +++ b/resources/lang/sl/countries.php @@ -68,4 +68,22 @@ 'helper' => 'Numerična šifra (ISO-3166)', ], ], + + 'import' => [ + 'action_label' => 'Uvozi države', + 'modal_heading' => 'Uvoz držav', + 'success_title' => 'Uvoz držav', + 'success_message' => 'Naloga za uvoz držav je bila dodana v čakalno vrsto.', + ], + + 'notifications' => [ + 'success' => [ + 'title' => 'Uvoz držav uspešno končan', + 'message' => 'Vse države so bile uspešno uvožene in posodobljene.', + ], + 'failed' => [ + 'title' => 'Uvoz držav neuspešen', + 'message' => 'Uvoz podatkov držav ni uspel.', + ], + ], ]; diff --git a/resources/lang/sl/posts.php b/resources/lang/sl/posts.php index 5403542..0003c25 100644 --- a/resources/lang/sl/posts.php +++ b/resources/lang/sl/posts.php @@ -75,4 +75,15 @@ 'HR' => 'Hrvaška', ], ], + + 'notifications' => [ + 'success' => [ + 'title' => 'Uvoz pošt uspešno končan', + 'message' => 'Poštni podatki za :country so bili uspešno uvoženi.', + ], + 'failed' => [ + 'title' => 'Uvoz pošt neuspešen', + 'message' => 'Uvoz poštnih podatkov za :country ni uspel.', + ], + ], ]; diff --git a/resources/lang/sr/countries.php b/resources/lang/sr/countries.php index 5e3cdb0..45247df 100644 --- a/resources/lang/sr/countries.php +++ b/resources/lang/sr/countries.php @@ -68,4 +68,22 @@ 'helper' => 'Numerička oznaka (ISO-3166)', ], ], + + 'import' => [ + 'action_label' => 'Uvezi države', + 'modal_heading' => 'Uvoz država', + 'success_title' => 'Uvoz država', + 'success_message' => 'Zadatak za uvoz država je dodat u red čekanja.', + ], + + 'notifications' => [ + 'success' => [ + 'title' => 'Uvoz država završen', + 'message' => 'Sve države su uspešno uvežene i ažurirane.', + ], + 'failed' => [ + 'title' => 'Uvoz država neuspešan', + 'message' => 'Neuspešan uvoz podataka država.', + ], + ], ]; diff --git a/resources/lang/sr/posts.php b/resources/lang/sr/posts.php index a65b5f3..0c0fbf1 100644 --- a/resources/lang/sr/posts.php +++ b/resources/lang/sr/posts.php @@ -75,4 +75,15 @@ 'HR' => 'Hrvatska', ], ], + + 'notifications' => [ + 'success' => [ + 'title' => 'Uvoz pošta završen', + 'message' => 'Poštanski podaci za :country su uspešno uveženi.', + ], + 'failed' => [ + 'title' => 'Uvoz pošta neuspešan', + 'message' => 'Neuspešan uvoz poštanskih podataka za :country.', + ], + ], ]; diff --git a/src/Filament/Clusters/World/Resources/CountryResource/Pages/ListCountries.php b/src/Filament/Clusters/World/Resources/CountryResource/Pages/ListCountries.php index e8e4e38..ae096ea 100644 --- a/src/Filament/Clusters/World/Resources/CountryResource/Pages/ListCountries.php +++ b/src/Filament/Clusters/World/Resources/CountryResource/Pages/ListCountries.php @@ -8,6 +8,7 @@ use Filament\Actions\CreateAction; use Filament\Notifications\Notification; use Filament\Resources\Pages\ListRecords; +use Illuminate\Support\Facades\App; class ListCountries extends ListRecords { @@ -24,7 +25,7 @@ protected function getHeaderActions(): array ->icon('heroicon-o-arrow-down-tray') ->action(function () { // Dispatch the job - ImportCountries::dispatch(); + ImportCountries::dispatch(auth()->id(), App::getLocale()); // Show notification Notification::make() diff --git a/src/Filament/Clusters/World/Resources/PostResource/Pages/ListPosts.php b/src/Filament/Clusters/World/Resources/PostResource/Pages/ListPosts.php index e037a45..92e82e3 100644 --- a/src/Filament/Clusters/World/Resources/PostResource/Pages/ListPosts.php +++ b/src/Filament/Clusters/World/Resources/PostResource/Pages/ListPosts.php @@ -9,6 +9,7 @@ use Filament\Forms\Components\Select; use Filament\Notifications\Notification; use Filament\Resources\Pages\ListRecords; +use Illuminate\Support\Facades\App; class ListPosts extends ListRecords { @@ -36,8 +37,8 @@ protected function getHeaderActions(): array ]) ->modalHeading(__('eclipse-world::posts.import.modal_heading')) ->action(function (array $data) { - // Dispatch the job with selected country - ImportPosts::dispatch($data['country_id']); + // Dispatch the job + ImportPosts::dispatch($data['country_id'], auth()->id(), App::getLocale()); // Show notification Notification::make() diff --git a/src/Jobs/ImportCountries.php b/src/Jobs/ImportCountries.php index 791c604..e34e2f2 100644 --- a/src/Jobs/ImportCountries.php +++ b/src/Jobs/ImportCountries.php @@ -2,12 +2,16 @@ namespace Eclipse\World\Jobs; +use Eclipse\Core\Models\User; use Eclipse\World\Models\Country; +use Eclipse\World\Notifications\ImportFinishedNotification; +use Exception; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; +use Illuminate\Support\Facades\Log; class ImportCountries implements ShouldQueue { @@ -17,32 +21,66 @@ class ImportCountries implements ShouldQueue public bool $failOnTimeout = true; + public ?int $userId; + + public string $locale; + + /** + * Create a new job instance. + */ + public function __construct(?int $userId, string $locale = 'en') + { + $this->userId = $userId; + $this->locale = $locale; + } + public function handle(): void { - // Load existing countries into an associative array - $existingCountries = Country::withTrashed()->get()->keyBy('id'); + Log::info('Starting countries import'); + + $user = $this->userId ? User::find($this->userId) : null; - // Load new country data - $countries = json_decode(file_get_contents('https://raw.githubusercontent.com/mledoze/countries/master/dist/countries.json'), true); + try { + // Load existing countries into an associative array + $existingCountries = Country::withTrashed()->get()->keyBy('id'); - foreach ($countries as $rawData) { - if (! $rawData['independent']) { - continue; + // Load new country data + $countries = json_decode(file_get_contents('https://raw.githubusercontent.com/mledoze/countries/master/dist/countries.json'), true); + + if (! $countries) { + throw new Exception('Failed to fetch or parse countries data'); + } + + foreach ($countries as $rawData) { + if (! $rawData['independent']) { + continue; + } + + $data = [ + 'id' => $rawData['cca2'], + 'a3_id' => $rawData['cca3'], + 'num_code' => $rawData['ccn3'], + 'name' => $rawData['name']['common'], + 'flag' => $rawData['flag'], + ]; + + if (isset($existingCountries[$data['id']])) { + $existingCountries[$data['id']]->update($data); + } else { + Country::create($data); + } } - $data = [ - 'id' => $rawData['cca2'], - 'a3_id' => $rawData['cca3'], - 'num_code' => $rawData['ccn3'], - 'name' => $rawData['name']['common'], - 'flag' => $rawData['flag'], - ]; - - if (isset($existingCountries[$data['id']])) { - $existingCountries[$data['id']]->update($data); - } else { - Country::create($data); + Log::info('Countries import completed'); + if ($user) { + $user->notify(new ImportFinishedNotification('success', 'countries', null, $this->locale)); + } + } catch (Exception $e) { + Log::error('Countries import failed: '.$e->getMessage()); + if ($user) { + $user->notify(new ImportFinishedNotification('failed', 'countries', null, $this->locale)); } + throw $e; } } } diff --git a/src/Jobs/ImportPosts.php b/src/Jobs/ImportPosts.php index ef19ac4..7f91303 100644 --- a/src/Jobs/ImportPosts.php +++ b/src/Jobs/ImportPosts.php @@ -2,7 +2,9 @@ namespace Eclipse\World\Jobs; +use Eclipse\Core\Models\User; use Eclipse\World\Models\Post; +use Eclipse\World\Notifications\ImportFinishedNotification; use Exception; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; @@ -20,12 +22,18 @@ class ImportPosts implements ShouldQueue public string $countryId; + public int $userId; + + public string $locale; + /** * Create a new job instance. */ - public function __construct(string $countryId) + public function __construct(string $countryId, int $userId, string $locale = 'en') { $this->countryId = $countryId; + $this->userId = $userId; + $this->locale = $locale; } /** @@ -43,37 +51,50 @@ public function handle(): void Log::info("Starting postal data import for country: {$this->countryId}"); - do { - [$totalRecords, $records] = $this->getData($batchSize, $offset); + $user = $this->userId ? User::find($this->userId) : null; - foreach ($records as $record) { - [$postalCode, $placeName] = $this->getRecordData($record); + try { + do { + [$totalRecords, $records] = $this->getData($batchSize, $offset); - if (array_key_exists($postalCode, $processedCodes)) { - continue; - } + foreach ($records as $record) { + [$postalCode, $placeName] = $this->getRecordData($record); + + if (array_key_exists($postalCode, $processedCodes)) { + continue; + } - $processedCodes[$postalCode] = true; + $processedCodes[$postalCode] = true; - $existingPost = Post::where('country_id', $this->countryId) - ->where('code', $postalCode) - ->first(); + $existingPost = Post::where('country_id', $this->countryId) + ->where('code', $postalCode) + ->first(); - if (empty($existingPost)) { - Post::create([ - 'country_id' => $this->countryId, - 'code' => $postalCode, - 'name' => $placeName, - ]); - } elseif ($existingPost->name !== $placeName) { - $existingPost->update(['name' => $placeName]); + if (empty($existingPost)) { + Post::create([ + 'country_id' => $this->countryId, + 'code' => $postalCode, + 'name' => $placeName, + ]); + } elseif ($existingPost->name !== $placeName) { + $existingPost->update(['name' => $placeName]); + } } - } - $offset += $batchSize; - } while ($offset < $totalRecords); + $offset += $batchSize; + } while ($offset < $totalRecords); - Log::info("Postal data import completed for {$this->countryId}"); + Log::info("Postal data import completed for {$this->countryId}"); + if ($user) { + $user->notify(new ImportFinishedNotification('success', 'posts', $this->countryId, $this->locale)); + } + } catch (Exception $e) { + Log::error("Postal data import failed for {$this->countryId}: {$e->getMessage()}"); + if ($user) { + $user->notify(new ImportFinishedNotification('failed', 'posts', $this->countryId, $this->locale)); + } + throw $e; + } } /** diff --git a/src/Notifications/ImportFinishedNotification.php b/src/Notifications/ImportFinishedNotification.php new file mode 100644 index 0000000..0c7a12b --- /dev/null +++ b/src/Notifications/ImportFinishedNotification.php @@ -0,0 +1,125 @@ +status = $status; + $this->importType = $importType; + $this->identifier = $identifier; + $this->locale = $locale; + } + + /** + * Channels: database only + */ + public function via(): array + { + return ['database']; + } + + /** + * For storing in DB + */ + public function toDatabase($notifiable): array + { + $title = $this->getTitle(); + $body = $this->getBody(); + $icon = $this->status === 'success' ? 'heroicon-o-check-circle' : 'heroicon-o-x-circle'; + $iconColor = $this->status === 'success' ? 'success' : 'danger'; + + $notification = FilamentNotification::make() + ->title($title) + ->body($body) + ->icon($icon) + ->iconColor($iconColor); + + $notification->broadcast($notifiable); + + return $notification->getDatabaseMessage(); + } + + public function toArray(): array + { + return [ + 'title' => $this->getTitle(), + 'body' => $this->getBody(), + 'status' => $this->status, + 'importType' => $this->importType, + 'identifier' => $this->identifier, + ]; + } + + /** + * Generate title based on import type and status using the locale + */ + private function getTitle(): string + { + $translationKey = "eclipse-world::{$this->importType}.notifications.{$this->status}.title"; + $title = __($translationKey, [], $this->locale); + + // Fallback to English if locale translation is missing + if ($title === $translationKey) { + $title = __($translationKey, [], 'en'); + } + + return $title; + } + + /** + * Generate body message based on import details using the locale + */ + private function getBody(): string + { + $translationKey = "eclipse-world::{$this->importType}.notifications.{$this->status}.message"; + + $parameters = []; + if ($this->identifier) { + if ($this->importType === 'posts') { + $countryKey = "eclipse-world::posts.import.countries.{$this->identifier}"; + $countryName = __($countryKey, [], $this->locale); + + // Fallback to English if locale translation is missing + if ($countryName === $countryKey) { + $countryName = __($countryKey, [], 'en'); + } + + // Final fallback to identifier itself (country code, e.g. SI) + if ($countryName === $countryKey) { + $countryName = $this->identifier; + } + + $parameters['country'] = $countryName; + } else { + $parameters['country'] = $this->identifier; + } + } + + $body = __($translationKey, $parameters, $this->locale); + + // Fallback to English if locale translation is missing + if ($body === $translationKey) { + $body = __($translationKey, $parameters, 'en'); + } + + return $body; + } +}