mirror of
https://github.com/openclassify/openclassify.git
synced 2026-04-14 11:12:09 -05:00
Fix create listing publish flow
This commit is contained in:
parent
6fde32cc8b
commit
46b70a91f7
@ -29,6 +29,7 @@ class PanelQuickListingForm extends Component
|
|||||||
|
|
||||||
private const TOTAL_STEPS = 5;
|
private const TOTAL_STEPS = 5;
|
||||||
private const DRAFT_SESSION_KEY = 'panel_quick_listing_draft';
|
private const DRAFT_SESSION_KEY = 'panel_quick_listing_draft';
|
||||||
|
private const OTHER_CITY_ID = -1;
|
||||||
|
|
||||||
public array $photos = [];
|
public array $photos = [];
|
||||||
public array $videos = [];
|
public array $videos = [];
|
||||||
@ -57,6 +58,7 @@ class PanelQuickListingForm extends Component
|
|||||||
public ?int $selectedCityId = null;
|
public ?int $selectedCityId = null;
|
||||||
public bool $isPublishing = false;
|
public bool $isPublishing = false;
|
||||||
public bool $shouldPersistDraft = true;
|
public bool $shouldPersistDraft = true;
|
||||||
|
public ?string $publishError = null;
|
||||||
|
|
||||||
public function mount(): void
|
public function mount(): void
|
||||||
{
|
{
|
||||||
@ -117,11 +119,13 @@ class PanelQuickListingForm extends Component
|
|||||||
|
|
||||||
public function goToStep(int $step): void
|
public function goToStep(int $step): void
|
||||||
{
|
{
|
||||||
|
$this->publishError = null;
|
||||||
$this->currentStep = max(1, min(self::TOTAL_STEPS, $step));
|
$this->currentStep = max(1, min(self::TOTAL_STEPS, $step));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function goToCategoryStep(): void
|
public function goToCategoryStep(): void
|
||||||
{
|
{
|
||||||
|
$this->publishError = null;
|
||||||
$this->validatePhotos();
|
$this->validatePhotos();
|
||||||
$this->validateVideos();
|
$this->validateVideos();
|
||||||
$this->currentStep = 2;
|
$this->currentStep = 2;
|
||||||
@ -133,12 +137,14 @@ class PanelQuickListingForm extends Component
|
|||||||
|
|
||||||
public function goToDetailsStep(): void
|
public function goToDetailsStep(): void
|
||||||
{
|
{
|
||||||
|
$this->publishError = null;
|
||||||
$this->validateCategoryStep();
|
$this->validateCategoryStep();
|
||||||
$this->currentStep = 3;
|
$this->currentStep = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function goToFeaturesStep(): void
|
public function goToFeaturesStep(): void
|
||||||
{
|
{
|
||||||
|
$this->publishError = null;
|
||||||
$this->validateCategoryStep();
|
$this->validateCategoryStep();
|
||||||
$this->validateDetailsStep();
|
$this->validateDetailsStep();
|
||||||
$this->currentStep = 4;
|
$this->currentStep = 4;
|
||||||
@ -146,6 +152,7 @@ class PanelQuickListingForm extends Component
|
|||||||
|
|
||||||
public function goToPreviewStep(): void
|
public function goToPreviewStep(): void
|
||||||
{
|
{
|
||||||
|
$this->publishError = null;
|
||||||
$this->validateCategoryStep();
|
$this->validateCategoryStep();
|
||||||
$this->validateDetailsStep();
|
$this->validateDetailsStep();
|
||||||
$this->validateCustomFieldsStep();
|
$this->validateCustomFieldsStep();
|
||||||
@ -199,6 +206,7 @@ class PanelQuickListingForm extends Component
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->publishError = null;
|
||||||
$this->selectedCategoryId = $categoryId;
|
$this->selectedCategoryId = $categoryId;
|
||||||
$this->loadListingCustomFields();
|
$this->loadListingCustomFields();
|
||||||
}
|
}
|
||||||
@ -210,6 +218,8 @@ class PanelQuickListingForm extends Component
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->isPublishing = true;
|
$this->isPublishing = true;
|
||||||
|
$this->publishError = null;
|
||||||
|
$this->resetErrorBag();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->validatePhotos();
|
$this->validatePhotos();
|
||||||
@ -221,11 +231,13 @@ class PanelQuickListingForm extends Component
|
|||||||
$listing = $this->createListing();
|
$listing = $this->createListing();
|
||||||
} catch (ValidationException $exception) {
|
} catch (ValidationException $exception) {
|
||||||
$this->isPublishing = false;
|
$this->isPublishing = false;
|
||||||
|
$this->handlePublishValidationFailure($exception);
|
||||||
|
|
||||||
throw $exception;
|
return;
|
||||||
} catch (Throwable $exception) {
|
} catch (Throwable $exception) {
|
||||||
report($exception);
|
report($exception);
|
||||||
$this->isPublishing = false;
|
$this->isPublishing = false;
|
||||||
|
$this->publishError = 'The listing could not be created. Please try again.';
|
||||||
session()->flash('error', 'The listing could not be created. Please try again.');
|
session()->flash('error', 'The listing could not be created. Please try again.');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -361,10 +373,20 @@ class PanelQuickListingForm extends Component
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return collect($this->cities)
|
$cities = collect($this->cities)
|
||||||
->where('country_id', $this->selectedCountryId)
|
->where('country_id', $this->selectedCountryId)
|
||||||
->values()
|
->values()
|
||||||
->all();
|
->all();
|
||||||
|
|
||||||
|
if ($cities !== []) {
|
||||||
|
return $cities;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [[
|
||||||
|
'id' => self::OTHER_CITY_ID,
|
||||||
|
'name' => 'Other',
|
||||||
|
'country_id' => $this->selectedCountryId,
|
||||||
|
]];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSelectedCountryNameProperty(): ?string
|
public function getSelectedCountryNameProperty(): ?string
|
||||||
@ -384,6 +406,10 @@ class PanelQuickListingForm extends Component
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((int) $this->selectedCityId === self::OTHER_CITY_ID) {
|
||||||
|
return 'Other';
|
||||||
|
}
|
||||||
|
|
||||||
$city = collect($this->cities)->firstWhere('id', $this->selectedCityId);
|
$city = collect($this->cities)->firstWhere('id', $this->selectedCityId);
|
||||||
|
|
||||||
return $city['name'] ?? null;
|
return $city['name'] ?? null;
|
||||||
@ -772,6 +798,49 @@ class PanelQuickListingForm extends Component
|
|||||||
return (string) config('media_storage.local_disk', MediaStorage::diskFromDriver(MediaStorage::DRIVER_LOCAL));
|
return (string) config('media_storage.local_disk', MediaStorage::diskFromDriver(MediaStorage::DRIVER_LOCAL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function handlePublishValidationFailure(ValidationException $exception): void
|
||||||
|
{
|
||||||
|
$errors = $exception->errors();
|
||||||
|
|
||||||
|
foreach ($errors as $key => $messages) {
|
||||||
|
foreach ($messages as $message) {
|
||||||
|
$this->addError($key, $message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->currentStep = $this->stepForValidationErrors(array_keys($errors));
|
||||||
|
$this->publishError = collect($errors)->flatten()->filter()->first() ?: 'Please fix the highlighted fields before publishing.';
|
||||||
|
}
|
||||||
|
|
||||||
|
private function stepForValidationErrors(array $keys): int
|
||||||
|
{
|
||||||
|
$normalizedKeys = collect($keys)->map(fn ($key) => (string) $key)->values();
|
||||||
|
|
||||||
|
if ($normalizedKeys->contains(fn ($key) => str_starts_with($key, 'photos') || str_starts_with($key, 'videos'))) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($normalizedKeys->contains('selectedCategoryId')) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($normalizedKeys->contains(fn ($key) => in_array($key, [
|
||||||
|
'listingTitle',
|
||||||
|
'price',
|
||||||
|
'description',
|
||||||
|
'selectedCountryId',
|
||||||
|
'selectedCityId',
|
||||||
|
], true))) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($normalizedKeys->contains(fn ($key) => str_starts_with($key, 'customFieldValues.'))) {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
private function restoreDraft(): void
|
private function restoreDraft(): void
|
||||||
{
|
{
|
||||||
$draft = session()->get($this->draftSessionKey(), []);
|
$draft = session()->get($this->draftSessionKey(), []);
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
@php
|
@php
|
||||||
$maxPhotoCount = (int) config('quick-listing.max_photo_count', 20);
|
$maxPhotoCount = (int) config('quick-listing.max_photo_count', 20);
|
||||||
|
$visiblePhotoSlotCount = min($maxPhotoCount, 8);
|
||||||
$maxVideoCount = (int) config('video.max_listing_videos', 5);
|
$maxVideoCount = (int) config('video.max_listing_videos', 5);
|
||||||
$currency = \Modules\Listing\Support\ListingPanelHelper::defaultCurrency();
|
$currency = \Modules\Listing\Support\ListingPanelHelper::defaultCurrency();
|
||||||
$displayPrice = is_numeric($price) ? number_format((float) $price, 0, ',', '.') : $price;
|
$displayPrice = is_numeric($price) ? number_format((float) $price, 0, ',', '.') : $price;
|
||||||
@ -737,6 +738,8 @@
|
|||||||
.qc-publish-stack {
|
.qc-publish-stack {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 0.7rem;
|
gap: 0.7rem;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.qc-button,
|
.qc-button,
|
||||||
@ -841,6 +844,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="qc-card">
|
<div class="qc-card">
|
||||||
|
@if ($publishError)
|
||||||
|
<div class="px-4 pt-4">
|
||||||
|
<div class="rounded-[18px] border border-rose-200 bg-rose-50 px-4 py-3 text-sm font-semibold text-rose-700">
|
||||||
|
{{ $publishError }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
@if ($currentStep === 1)
|
@if ($currentStep === 1)
|
||||||
<div class="qc-body">
|
<div class="qc-body">
|
||||||
<div class="qc-stack">
|
<div class="qc-stack">
|
||||||
@ -880,7 +891,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="qc-photo-grid">
|
<div class="qc-photo-grid">
|
||||||
@for ($index = 0; $index < $maxPhotoCount; $index++)
|
@for ($index = 0; $index < $visiblePhotoSlotCount; $index++)
|
||||||
<div class="qc-photo-slot">
|
<div class="qc-photo-slot">
|
||||||
@if (isset($photos[$index]))
|
@if (isset($photos[$index]))
|
||||||
<img src="{{ $photos[$index]->temporaryUrl() }}" alt="Uploaded photo {{ $index + 1 }}">
|
<img src="{{ $photos[$index]->temporaryUrl() }}" alt="Uploaded photo {{ $index + 1 }}">
|
||||||
@ -894,6 +905,10 @@
|
|||||||
</div>
|
</div>
|
||||||
@endfor
|
@endfor
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@if (count($photos) > $visiblePhotoSlotCount)
|
||||||
|
<p class="qc-meta-copy mt-3">{{ count($photos) - $visiblePhotoSlotCount }} more photos added.</p>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
<div class="qc-empty">Add one cover photo to continue.</div>
|
<div class="qc-empty">Add one cover photo to continue.</div>
|
||||||
@ -1322,10 +1337,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="qc-panel">
|
<div class="qc-panel">
|
||||||
<form class="qc-publish-stack" wire:submit.prevent="publishListing">
|
<div class="qc-publish-stack">
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="button"
|
||||||
class="qc-button"
|
class="qc-button"
|
||||||
|
wire:click.prevent="publishListing"
|
||||||
wire:loading.attr="disabled"
|
wire:loading.attr="disabled"
|
||||||
wire:target="publishListing"
|
wire:target="publishListing"
|
||||||
>
|
>
|
||||||
@ -1333,7 +1349,7 @@
|
|||||||
<span wire:loading wire:target="publishListing">Publishing...</span>
|
<span wire:loading wire:target="publishListing">Publishing...</span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="qc-button-secondary" wire:click="goToStep(4)" wire:loading.attr="disabled" wire:target="publishListing">Back</button>
|
<button type="button" class="qc-button-secondary" wire:click="goToStep(4)" wire:loading.attr="disabled" wire:target="publishListing">Back</button>
|
||||||
</form>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user