This commit is contained in:
+65
-1
@@ -14240,6 +14240,7 @@ function AddListingPage({ editListingId }: { editListingId?: number }) {
|
|||||||
// dalej, zeby nie krzyczec o brakach zanim uzytkownik cokolwiek wypelni.
|
// dalej, zeby nie krzyczec o brakach zanim uzytkownik cokolwiek wypelni.
|
||||||
const [showDetailsError, setShowDetailsError] = useState(false);
|
const [showDetailsError, setShowDetailsError] = useState(false);
|
||||||
const [showLocationError, setShowLocationError] = useState(false);
|
const [showLocationError, setShowLocationError] = useState(false);
|
||||||
|
const [showPhotosError, setShowPhotosError] = useState(false);
|
||||||
const [listingDetails, setListingDetails] = useState(INITIAL_LISTING_DETAILS);
|
const [listingDetails, setListingDetails] = useState(INITIAL_LISTING_DETAILS);
|
||||||
// Ekran startowy z wyborem "Chcę sprzedać / wynająć" + kategorii. Przy edycji pomijamy go i od razu
|
// Ekran startowy z wyborem "Chcę sprzedać / wynająć" + kategorii. Przy edycji pomijamy go i od razu
|
||||||
// pokazujemy formularz. Wybor kategorii ustawia transakcje i rodzaj, a potem wchodzimy w kreator.
|
// pokazujemy formularz. Wybor kategorii ustawia transakcje i rodzaj, a potem wchodzimy w kreator.
|
||||||
@@ -14640,8 +14641,17 @@ function AddListingPage({ editListingId }: { editListingId?: number }) {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Krok "Zdjęcia" (currentStep 2) - wymagamy przynajmniej jednego zdjecia, zeby przejsc dalej.
|
||||||
|
if (currentStep === 2 && step > 2 && photos.length === 0) {
|
||||||
|
setShowPhotosError(true);
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
document.querySelector('.add-step-error')?.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
setShowDetailsError(false);
|
setShowDetailsError(false);
|
||||||
setShowLocationError(false);
|
setShowLocationError(false);
|
||||||
|
setShowPhotosError(false);
|
||||||
setCurrentStep(step);
|
setCurrentStep(step);
|
||||||
window.requestAnimationFrame(() => {
|
window.requestAnimationFrame(() => {
|
||||||
document.querySelector('.add-page')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
document.querySelector('.add-page')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||||
@@ -15328,6 +15338,12 @@ function AddListingPage({ editListingId }: { editListingId?: number }) {
|
|||||||
{virtualTourError && <p className="photo-tour-error" role="alert">{virtualTourError}</p>}
|
{virtualTourError && <p className="photo-tour-error" role="alert">{virtualTourError}</p>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{showPhotosError && photos.length === 0 && (
|
||||||
|
<p className="add-field-error add-step-error" role="alert">
|
||||||
|
Dodaj przynajmniej jedno zdjęcie, aby przejść dalej.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="add-location-actions photos-actions">
|
<div className="add-location-actions photos-actions">
|
||||||
<button className="back-step-button" type="button" onClick={() => goToStep(1)}>
|
<button className="back-step-button" type="button" onClick={() => goToStep(1)}>
|
||||||
Wstecz
|
Wstecz
|
||||||
@@ -22518,6 +22534,45 @@ function ResultCardGallery({ photos, cover, alt }: { photos: string[]; cover: st
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Animacja wczytywania listy ofert - pokazywana zamiast pustego miejsca, dopoki backend nie odda
|
||||||
|
// ogloszen. Znika sama, gdy dane przyjda (komponent nadrzedny przestaje ja renderowac).
|
||||||
|
function ListingsLoader() {
|
||||||
|
return (
|
||||||
|
<div className="listings-loader" role="status" aria-live="polite">
|
||||||
|
<div className="listings-loader-art" aria-hidden="true">
|
||||||
|
<svg viewBox="0 0 240 150" width="200" height="125" role="img">
|
||||||
|
<path d="M42 118a78 78 0 0 1 156 0Z" fill="#e8f5ed" />
|
||||||
|
<g className="ll-cloud ll-cloud-a" fill="#eef2f6">
|
||||||
|
<ellipse cx="58" cy="44" rx="17" ry="9" />
|
||||||
|
<ellipse cx="70" cy="40" rx="12" ry="8" />
|
||||||
|
</g>
|
||||||
|
<g className="ll-cloud ll-cloud-b" fill="#eef2f6">
|
||||||
|
<ellipse cx="188" cy="52" rx="15" ry="8" />
|
||||||
|
<ellipse cx="177" cy="48" rx="10" ry="7" />
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<rect x="58" y="96" width="7" height="22" rx="3" fill="#c3ddca" />
|
||||||
|
<circle cx="61.5" cy="90" r="16" fill="#d4ead9" />
|
||||||
|
</g>
|
||||||
|
<g className="ll-house">
|
||||||
|
<rect x="96" y="86" width="60" height="34" rx="3" fill="#ffffff" stroke="#cadfd2" strokeWidth="2.5" />
|
||||||
|
<path d="M126 58l34 30H92Z" fill="#d4ead9" stroke="#9ecfae" strokeWidth="2.5" strokeLinejoin="round" />
|
||||||
|
<rect x="150" y="66" width="8" height="16" rx="2" fill="#c3ddca" />
|
||||||
|
<rect x="118" y="98" width="16" height="22" rx="2" fill="#38b26a" />
|
||||||
|
<circle cx="130" cy="109" r="1.6" fill="#ffffff" />
|
||||||
|
</g>
|
||||||
|
<rect x="42" y="117" width="156" height="3" rx="1.5" fill="#d9ebe0" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<p className="listings-loader-title">Wczytujemy <span>ogłoszenia</span>…</p>
|
||||||
|
<p className="listings-loader-sub">Zaraz pokażemy Ci najlepsze oferty dopasowane do Twoich kryteriów.</p>
|
||||||
|
<div className="listings-loader-bars" aria-hidden="true">
|
||||||
|
<span /><span /><span /><span />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function RealListingsBand({
|
function RealListingsBand({
|
||||||
offerType,
|
offerType,
|
||||||
onOpenListing,
|
onOpenListing,
|
||||||
@@ -22553,7 +22608,16 @@ function RealListingsBand({
|
|||||||
const cityFilter = (city ?? '').trim();
|
const cityFilter = (city ?? '').trim();
|
||||||
const visible = cityFilter ? items.filter((item) => cityStartsWith(item.city, cityFilter)) : items;
|
const visible = cityFilter ? items.filter((item) => cityStartsWith(item.city, cityFilter)) : items;
|
||||||
|
|
||||||
if (loading || visible.length === 0) {
|
// W trakcie ladowania pokazujemy animacje zamiast pustego miejsca; gdy dane przyjda i lista jest
|
||||||
|
// pusta - nie pokazujemy nic (jak dotad).
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<div className="real-listings-section" aria-label="Ogłoszenia dodane w serwisie">
|
||||||
|
<ListingsLoader />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (visible.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26568,6 +26568,107 @@ a.city-card:hover {
|
|||||||
margin-bottom: 18px;
|
margin-bottom: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Animacja wczytywania ofert - wypelnia miejsce listy, dopoki backend nie odda ogloszen. */
|
||||||
|
.listings-loader {
|
||||||
|
align-items: center;
|
||||||
|
background: linear-gradient(180deg, #f6faf7 0%, #ffffff 100%);
|
||||||
|
border: 1px solid #e7eef0;
|
||||||
|
border-radius: 16px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
margin-top: 18px;
|
||||||
|
padding: 30px 24px 34px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listings-loader-art {
|
||||||
|
animation: ll-float 2.6s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ll-house {
|
||||||
|
animation: ll-pop 2.6s ease-in-out infinite;
|
||||||
|
transform-origin: 126px 118px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ll-cloud-a { animation: ll-drift 5s ease-in-out infinite; }
|
||||||
|
.ll-cloud-b { animation: ll-drift 6.5s ease-in-out infinite reverse; }
|
||||||
|
|
||||||
|
.listings-loader-title {
|
||||||
|
color: #13243d;
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 900;
|
||||||
|
margin: 6px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listings-loader-title span { color: #10a15e; }
|
||||||
|
|
||||||
|
.listings-loader-sub {
|
||||||
|
color: #7b8896;
|
||||||
|
font-size: 14px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listings-loader-bars {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listings-loader-bars span {
|
||||||
|
background: #e4ebe6;
|
||||||
|
border-radius: 999px;
|
||||||
|
height: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 46px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listings-loader-bars span::after {
|
||||||
|
animation: ll-fill 1.4s ease-in-out infinite;
|
||||||
|
background: #10a15e;
|
||||||
|
border-radius: inherit;
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
transform: translateX(-100%);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listings-loader-bars span:nth-child(2)::after { animation-delay: 0.18s; }
|
||||||
|
.listings-loader-bars span:nth-child(3)::after { animation-delay: 0.36s; }
|
||||||
|
.listings-loader-bars span:nth-child(4)::after { animation-delay: 0.54s; }
|
||||||
|
|
||||||
|
@keyframes ll-float {
|
||||||
|
0%, 100% { transform: translateY(0); }
|
||||||
|
50% { transform: translateY(-6px); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes ll-pop {
|
||||||
|
0%, 100% { transform: scale(1); }
|
||||||
|
50% { transform: scale(1.04); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes ll-drift {
|
||||||
|
0%, 100% { transform: translateX(0); }
|
||||||
|
50% { transform: translateX(6px); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes ll-fill {
|
||||||
|
0% { transform: translateX(-100%); }
|
||||||
|
55%, 100% { transform: translateX(100%); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.listings-loader-art,
|
||||||
|
.ll-house,
|
||||||
|
.ll-cloud-a,
|
||||||
|
.ll-cloud-b,
|
||||||
|
.listings-loader-bars span::after {
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
.listings-loader-bars span::after { transform: translateX(0); }
|
||||||
|
}
|
||||||
|
|
||||||
.real-listings-heading {
|
.real-listings-heading {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -30956,6 +31057,19 @@ a.listing-detail-back {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Widok KOMPAKTOWY: gestsze wiersze, mniejsze zdjecie, bez metadanych. */
|
/* Widok KOMPAKTOWY: gestsze wiersze, mniejsze zdjecie, bez metadanych. */
|
||||||
|
/* Widok LISTA (domyslny): karty nieco wieksze niz bazowe - szersze zdjecie i wyzszy kafelek.
|
||||||
|
Tylko od 761px w gore, zeby nie ruszac ukladu mobilnego (ponizej 760px karty i tak sie skladaja). */
|
||||||
|
@media (min-width: 761px) {
|
||||||
|
.result-list.view-lista .result-card {
|
||||||
|
grid-template-columns: 320px minmax(0, 1fr) 190px;
|
||||||
|
min-height: 232px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-list.view-lista .result-photo {
|
||||||
|
min-height: 232px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.result-list.view-kompaktowa { gap: 8px; }
|
.result-list.view-kompaktowa { gap: 8px; }
|
||||||
|
|
||||||
.result-list.view-kompaktowa .result-card {
|
.result-list.view-kompaktowa .result-card {
|
||||||
|
|||||||
Reference in New Issue
Block a user