diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 528c280..a12c25b 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -2129,31 +2129,37 @@ function articleCountLabel(count: number): string { return `${count} artykułów`; } +// Skroty do wbudowanych poradnikow - kazdy prowadzi do rozdzialu, ktory opisuje dany temat. const quickGuides = [ { icon: 'scale', title: 'Jak sprawdzić księgę wieczystą?', text: 'Poradnik krok po kroku', + to: ROUTES.guideLaw, }, { icon: 'percent', title: 'Podatek od sprzedaży mieszkania', text: 'Kiedy trzeba zapłacić?', + to: ROUTES.guideLaw, }, { icon: 'paint', title: 'Ile kosztuje remont mieszkania?', text: 'Aktualne koszty robocizny i materiałów', + to: ROUTES.guideRenovation, }, { icon: 'shield', title: 'Jak bezpiecznie wynająć mieszkanie?', text: 'Porady dla wynajmujących', + to: ROUTES.guideRent, }, { icon: 'chart', title: 'PCC przy zakupie mieszkania', text: 'Stawki i zwolnienia w 2026 roku', + to: ROUTES.guideLaw, }, ]; @@ -6497,10 +6503,10 @@ function AccountSidebar() {
- Konto Premium + Konto Premium Wkrótce

Zyskaj dostęp do dodatkowych narzędzi i raportów.

- +
); @@ -6816,7 +6822,6 @@ function AccountDashboardPage({ ))} - ), }; @@ -7180,23 +7185,16 @@ function AccountHelpContactPage({ text: string; }; + // Kanaly kontaktu: e-mail i telefon otwieraja program pocztowy albo dzwonia, formularz jest nizej na stronie. const supportChannels = [ - { - id: 'live-chat', - icon: 'message', - iconTone: 'green', - title: 'Czat na żywo', - badge: 'Najszybsza pomoc', - description: 'Porozmawiaj z naszym konsultantem w czasie rzeczywistym.', - action: 'Dostępny 8:00 - 20:00', - }, { id: 'email', icon: 'mail', iconTone: 'blue', title: 'E-mail', description: 'Napisz do nas, odpowiemy najszybciej jak to możliwe.', - action: 'bok@polskalokalnie.pl', + action: SUPPORT_EMAIL, + href: `mailto:${SUPPORT_EMAIL}`, }, { id: 'phone', @@ -7204,7 +7202,8 @@ function AccountHelpContactPage({ iconTone: 'violet', title: 'Telefon', description: 'Zadzwoń do nas, chętnie odpowiemy na Twoje pytania.', - action: '+48 22 123 45 67', + action: SUPPORT_PHONE, + href: SUPPORT_PHONE_HREF, }, { id: 'form', @@ -7216,14 +7215,33 @@ function AccountHelpContactPage({ }, ] as const; + // Odpowiedzi opisuja to, co serwis naprawde robi - kazda prowadzi do wlasciwej strony. const faqItems = [ - 'Jak dodać ogłoszenie?', - 'Ile kosztuje dodanie ogłoszenia?', - 'Jak wyróżnić moje ogłoszenie?', - 'Jak edytować lub usunąć ogłoszenie?', - 'Jak działa porównywarka mieszkań?', - 'Jak ustawić alerty cenowe?', - ] as const; + { + question: 'Jak dodać ogłoszenie?', + answer: <>Wypełnij formularz na stronie Dodaj ogłoszenie. Po wysłaniu ogłoszenie czeka na akceptację obsługi i dopiero potem pojawia się na liście ofert., + }, + { + question: 'Ile kosztuje dodanie ogłoszenia?', + answer: <>Nic. Dodanie i publikacja ogłoszenia są bezpłatne, nie pobieramy prowizji od sprzedaży. Płatne jest tylko dobrowolne wyróżnienie oferty., + }, + { + question: 'Jak wyróżnić moje ogłoszenie?', + answer: <>W panelu Moje oferty kliknij „Wyróżnij” przy zaakceptowanym ogłoszeniu. Wybierzesz czas wyróżnienia i zapłacisz przez AutoPay albo użyjesz kredytów z wcześniej kupionego pakietu., + }, + { + question: 'Jak edytować lub usunąć ogłoszenie?', + answer: <>Obie opcje są w panelu Moje oferty, przy każdym ogłoszeniu. Po edycji ogłoszenie ponownie trafia do akceptacji., + }, + { + question: 'Jak działa porównywarka mieszkań?', + answer: <>Na liście ofert dodajesz mieszkania do porównania, a w Porównaniu widzisz je obok siebie: cenę, metraż, cenę za m² i pozostałe parametry., + }, + { + question: 'Jak ustawić alerty cenowe?', + answer: <>Alert ceny ogłoszenia założysz przyciskiem na karcie oferty, a alert lokalizacji w Historii cen. Wszystkie zobaczysz w panelu Alerty cenowe. Nie wysyłamy jeszcze powiadomień e-mail., + }, + ]; const moreHelpCards = [ { @@ -7421,18 +7439,24 @@ function AccountHelpContactPage({

{channel.title}

- {'badge' in channel && channel.badge ? {channel.badge} : null}

{channel.description}

- + {'href' in channel && channel.href ? ( + + {channel.action} + + + ) : ( + + )} ))} @@ -7442,16 +7466,16 @@ function AccountHelpContactPage({

Najczęściej zadawane pytania

- + Poradniki
- {faqItems.map((question) => ( -
+ {faqItems.map((item) => ( +
- {question} + {item.question} -

Znajdziesz odpowiedź w naszym centrum pomocy. W razie potrzeby skorzystaj z formularza kontaktowego obok.

+

{item.answer}

))}
@@ -8213,7 +8237,7 @@ function AccountPriceAlertsPage({

Twoje alerty

-

Obserwowane ogłoszenia — powiadomimy Cię, gdy zmieni się ich cena

+

Obserwowane ogłoszenia — zmiany ich cen zobaczysz tutaj

Dodaj z ogłoszenia @@ -8367,14 +8391,40 @@ function AccountComparisonPage({ onOpenListing }: { onOpenListing: (id: number) const [propertyTypeFilter, setPropertyTypeFilter] = useState('ALL'); const [search, setSearch] = useState(''); const [pickerValue, setPickerValue] = useState(''); - const [selectedIds, setSelectedIds] = useState([]); + // Wybrane oferty siedza w adresie (?oferty=1,4), wiec porownanie przezywa odswiezenie + // i da sie je wyslac linkiem ("Udostepnij porownanie"). + const [comparisonParams, setComparisonParams] = useSearchParams(); + const selectedIds = (comparisonParams.get('oferty') ?? '') + .split(',') + .map(Number) + .filter((id) => Number.isInteger(id) && id > 0); + const setSelectedIds = (update: number[] | ((current: number[]) => number[])) => { + const next = typeof update === 'function' ? update(selectedIds) : update; + setComparisonParams((prev) => { + const params = new URLSearchParams(prev); + if (next.length > 0) { + params.set('oferty', next.join(',')); + } else { + params.delete('oferty'); + } + return params; + }, { replace: true }); + }; const [selectedDetails, setSelectedDetails] = useState>({}); + const [shareInfo, setShareInfo] = useState(''); const [valuesGridOffset, setValuesGridOffset] = useState(0); const summaryFirstMetricRef = useRef(null); const firstValueCellRef = useRef(null); const { items, loading } = useLiveListings(offerType); + // Przelaczenie sprzedaz/najem czysci wybor, ale nie przy pierwszym wejsciu - inaczej + // skasowaloby oferty podane w adresie (udostepniony link). + const comparisonMountedRef = useRef(false); useEffect(() => { + if (!comparisonMountedRef.current) { + comparisonMountedRef.current = true; + return; + } setSelectedIds([]); setPickerValue(''); setSearch(''); @@ -8382,8 +8432,12 @@ function AccountComparisonPage({ onOpenListing }: { onOpenListing: (id: number) }, [offerType]); useEffect(() => { + // Dopiero gdy lista ofert dotarla - na pustej liscie skasowalibysmy wybor z adresu. + if (loading || items.length === 0) { + return; + } setSelectedIds((current) => current.filter((id) => items.some((item) => item.id === id))); - }, [items]); + }, [items, loading]); useEffect(() => { if (selectedIds.length === 0) { @@ -8773,10 +8827,23 @@ function AccountComparisonPage({ onOpenListing }: { onOpenListing: (id: number)

Porównaj do 4 mieszkań i wybierz najlepszą ofertę dla siebie.

- +
+ {shareInfo &&

{shareInfo}

}
@@ -13181,13 +13250,11 @@ function HomePage({ filters, onOpenMap }: { filters: FilterState; onOpenMap: (ci ))} -
+ Zobacz wszystkie miasta - 500+ lokalizacji - -
+ Cała Polska na mapie + + @@ -13248,6 +13315,16 @@ function RentPage({ const { city, propertyType, pMin, pMax, aMin, aMax, rooms, wtorny, pierwotny, chips, resetAll } = filters; const { formatPrice } = useDisplay(); const [, setSearchParams] = useSearchParams(); + // "Szukaj na bieżącej mapie": numery ofert widocznych na mapie trafiaja do adresu (?obszar=...), + // wiec zawezony wynik przezywa odswiezenie. Myslnik = na mapie nie bylo zadnej oferty. + const searchVisibleOnMap = (offerIds: number[]) => { + setSearchParams((prev) => { + const next = new URLSearchParams(prev); + next.set('obszar', offerIds.length > 0 ? offerIds.join(',') : '-'); + next.delete('strona'); + return next; + }); + }; const [isMapOpen, setIsMapOpen] = useState(false); const [studentOnly, setStudentOnly] = useState(false); const [petsOnly, setPetsOnly] = useState(false); @@ -13387,6 +13464,7 @@ function RentPage({ cityLabel={city || 'Warszawa'} geoMarkers={rentGeoMarkers} onMapClick={() => setIsMapOpen(true)} + onSearchVisible={searchVisibleOnMap} /> @@ -13394,9 +13472,10 @@ function RentPage({
AI Dopasowanie + Wkrótce

Powiedz nam, czego szukasz, a AI znajdzie dla Ciebie idealne oferty wynajmu.

- @@ -14990,18 +15069,18 @@ function AddListingPage({ editListingId }: { editListingId?: number }) {

- +48 123 456 789 + {SUPPORT_PHONE} Pon. - Pt. 9:00 - 17:00

- pomoc@polskalokalnie.pl + {SUPPORT_EMAIL} Odpowiadamy w ciągu 24h

- + Najczęściej zadawane pytania )} @@ -16081,6 +16160,25 @@ function GuideArticleTemplate({ content }: { content: GuideContent }) { ); } +// Kafelek artykulu uzytkownika - ten sam w polecanych i w wynikach wyszukiwania. +function ArticleTile({ article }: { article: ArticleCard }) { + return ( + +
+ {guideTopicBySlug(article.topicSlug)?.title.toUpperCase() ?? 'PORADNIK'} +
+
+

{article.title}

+

{article.excerpt}

+
+ {article.readMinutes} min czytania + {article.views} +
+
+ + ); +} + function GuidesPage() { const navigate = useNavigate(); // Liczba artykułów użytkowników w każdym temacie. Do tego doliczamy 1 wbudowany poradnik. @@ -16092,9 +16190,9 @@ function GuidesPage() { .catch(() => { /* brak sieci - licznik pokaże sam wbudowany poradnik */ }); return () => { cancelled = true; }; }, []); - // Polecane artykuly: najczesciej czytane artykuly uzytkownikow ze wszystkich tematow. - // API zwraca artykuly per temat, wiec laczymy odpowiedzi dla kazdego tematu. - const [featuredArticles, setFeaturedArticles] = useState(null); + // Wszystkie artykuly uzytkownikow - API zwraca je per temat, wiec laczymy odpowiedzi. + // Z tej listy bierzemy polecane (najczesciej czytane) i wyniki wyszukiwania. + const [allArticles, setAllArticles] = useState(null); useEffect(() => { let cancelled = false; Promise.all(GUIDE_TOPICS.map((topic) => ( @@ -16102,11 +16200,32 @@ function GuidesPage() { ))) .then((perTopic) => { if (!cancelled) { - setFeaturedArticles(perTopic.flat().sort((left, right) => right.views - left.views).slice(0, 4)); + setAllArticles(perTopic.flat()); } }); return () => { cancelled = true; }; }, []); + const featuredArticles = allArticles && [...allArticles].sort((left, right) => right.views - left.views).slice(0, 4); + + // Szukana fraza siedzi w adresie (/poradniki?szukaj=...), wiec wynik da sie odswiezyc i udostepnic. + const [guideParams, setGuideParams] = useSearchParams(); + const guideQuery = guideParams.get('szukaj') ?? ''; + const [guideSearchDraft, setGuideSearchDraft] = useState(guideQuery); + useEffect(() => { + setGuideSearchDraft(guideQuery); + }, [guideQuery]); + const submitGuideSearch = (event: ReactFormEvent) => { + event.preventDefault(); + const phrase = guideSearchDraft.trim(); + setGuideParams(phrase ? { szukaj: phrase } : {}); + }; + const normalizedQuery = guideQuery.trim().toLowerCase(); + const matchingArticles = normalizedQuery.length > 0 && allArticles + ? allArticles.filter((article) => `${article.title} ${article.excerpt}`.toLowerCase().includes(normalizedQuery)) + : []; + const matchingTopics = normalizedQuery.length > 0 + ? GUIDE_TOPICS.filter((topic) => topic.title.toLowerCase().includes(normalizedQuery)) + : []; return (
@@ -16116,11 +16235,16 @@ function GuidesPage() {

Centrum wiedzy o nieruchomościach

Praktyczne poradniki, analizy rynku i eksperckie wskazówki, które pomogą Ci podjąć najlepsze decyzje.

-
+
- - -
+ setGuideSearchDraft(event.target.value)} + aria-label="Szukaj w poradnikach" + /> + +
Popularne: Kredyt hipoteczny @@ -16134,13 +16258,43 @@ function GuidesPage() {
-
+ {normalizedQuery.length > 0 && ( +
+
+

Wyniki dla „{guideQuery.trim()}”

+ Wyczyść wyszukiwanie +
+ {matchingTopics.length > 0 && ( +
+ {matchingTopics.map((topic) => ( + + + + + {topic.title} + + ))} +
+ )} + {matchingArticles.length > 0 ? ( +
+ {matchingArticles.map((article) => ( + + ))} +
+ ) : ( + matchingTopics.length === 0 && ( +

+ {allArticles == null ? 'Szukamy…' : 'Nie znaleźliśmy artykułu ani tematu z tą frazą. Sprawdź tematy poniżej.'} +

+ ) + )} +
+ )} + +

Wybierz temat

-
- - -
{guideTopics.map((topic) => { @@ -16174,23 +16328,7 @@ function GuidesPage() { ) : (
{(featuredArticles ?? []).map((article) => ( - -
- {guideTopicBySlug(article.topicSlug)?.title.toUpperCase() ?? 'PORADNIK'} -
-
-

{article.title}

-

{article.excerpt}

-
- {article.readMinutes} min czytania - {article.views} -
-
- + ))}
)} @@ -16236,7 +16374,7 @@ function GuidesPage() {

Szybkie poradniki

{quickGuides.map((guide) => ( -
+ @@ -16245,13 +16383,13 @@ function GuidesPage() { {guide.text}

-
+ ))}
- +
@@ -17034,7 +17172,7 @@ function SellPage() {

Zobacz opinie naszych użytkowników

- {sellTestimonials.map((testimonial, index) => ( + {sellTestimonials.map((testimonial) => (
{testimonial.name.charAt(0)} @@ -17050,15 +17188,9 @@ function SellPage() { ))} 5.0
- {index === 0 && } - {index === 2 && }
))}
-
- - -
@@ -22086,7 +22218,17 @@ function RealListingsBand({ }, [sortOpen]); const cityFilter = (city ?? '').trim(); - const visible = cityFilter ? items.filter((item) => cityStartsWith(item.city, cityFilter)) : items; + const byCity = cityFilter ? items.filter((item) => cityStartsWith(item.city, cityFilter)) : items; + // "Szukaj na bieżącej mapie" wpisuje numery widocznych ofert do adresu (?obszar=1,4,9), + // dzieki czemu zawezony wynik przezywa odswiezenie i da sie go wyslac linkiem. + const areaParam = searchParams.get('obszar'); + const areaIds = areaParam ? new Set(areaParam.split(',').map(Number).filter((id) => !Number.isNaN(id))) : null; + const visible = areaIds ? byCity.filter((item) => areaIds.has(item.id)) : byCity; + const clearArea = () => { + const next = new URLSearchParams(searchParams); + next.delete('obszar'); + setSearchParams(next); + }; // W trakcie ladowania pokazujemy animacje zamiast pustego miejsca; gdy dane przyjda i lista jest // pusta - nie pokazujemy nic (jak dotad). @@ -22098,7 +22240,16 @@ function RealListingsBand({ ); } if (visible.length === 0) { - return null; + // Pusto po zawezeniu do obszaru mapy to co innego niz brak ofert - trzeba dac droge powrotna. + return areaIds ? ( +
+

+ + Na widocznym fragmencie mapy nie ma żadnej oferty. + +

+
+ ) : null; } // Widok prezentacji (lista/kompaktowa/kafelki) oraz numer strony trzymamy w query @@ -22155,6 +22306,13 @@ function RealListingsBand({ return (
+ {areaIds && ( +

+ + Pokazujemy oferty widoczne na mapie. + +

+ )}

Ogłoszenia dodane w serwisie

{visible.length} @@ -22376,6 +22534,16 @@ function BuyPage({ }) { const { city, propertyType, pMin, pMax, aMin, aMax, rooms, wtorny, pierwotny, noFeeOnly, chips, resetAll, fromPreferences } = filters; const [searchParams, setSearchParams] = useSearchParams(); + // "Szukaj na bieżącej mapie": numery ofert widocznych na mapie trafiaja do adresu (?obszar=...), + // wiec zawezony wynik przezywa odswiezenie. Myslnik = na mapie nie bylo zadnej oferty. + const searchVisibleOnMap = (offerIds: number[]) => { + setSearchParams((prev) => { + const next = new URLSearchParams(prev); + next.set('obszar', offerIds.length > 0 ? offerIds.join(',') : '-'); + next.delete('strona'); + return next; + }); + }; const [isMapOpen, setIsMapOpen] = useState(false); // Miasto przekazane w adresie (np. z kafelka miasta na stronie glownej: /kupno?miasto=Warszawa) @@ -22510,6 +22678,7 @@ function BuyPage({ cityLabel={city || 'Warszawa'} geoMarkers={saleGeoMarkers} onMapClick={() => setIsMapOpen(true)} + onSearchVisible={searchVisibleOnMap} />
@@ -22517,9 +22686,10 @@ function BuyPage({
AI Dopasowanie + Wkrótce

Powiedz nam czego szukasz, a AI znajdzie oferty idealnie dopasowane do Ciebie.

- @@ -22591,6 +22761,7 @@ function SatelliteMap({ geoMarkers, onMapClick, onMarkerClick, + onSearchVisible, size, areaRadiusMeters, }: { @@ -22603,6 +22774,8 @@ function SatelliteMap({ geoMarkers?: { id: string; lat: number; lng: number; label: string; offerId?: number }[]; onMapClick?: () => void; onMarkerClick?: (offerId: number) => void; + // Zawezenie listy ofert do tych, ktore widac na mapie. Bez tej funkcji przycisku nie pokazujemy. + onSearchVisible?: (offerIds: number[]) => void; size?: number; // Podany promien (w metrach) zastepuje pinezke kolem - uzywany dla przyblizonej lokalizacji. areaRadiusMeters?: number; @@ -22790,10 +22963,21 @@ function SatelliteMap({ ))}
- + {onSearchVisible && ( + + )} {areaCircle && ( span { +.quick-guides-card :is(article, a) > span { align-items: center; background: #edf3ff; border-radius: 8px; @@ -4174,17 +4174,17 @@ a.city-card:hover { width: 34px; } -.quick-guides-card article:nth-child(2) > span { +.quick-guides-card :is(article, a):nth-child(2) > span { background: #f1edff; color: #9b5cff; } -.quick-guides-card article:nth-child(3) > span { +.quick-guides-card :is(article, a):nth-child(3) > span { background: #fff4df; color: #f49a31; } -.quick-guides-card article:nth-child(4) > span { +.quick-guides-card :is(article, a):nth-child(4) > span { background: #e9f8ef; color: #10a15e; } @@ -4208,7 +4208,7 @@ a.city-card:hover { margin-top: 3px; } -.quick-guides-card article > svg { +.quick-guides-card :is(article, a) > svg { color: #9aa5b4; transform: rotate(-90deg); } @@ -9475,50 +9475,6 @@ a.city-card:hover { margin-left: 6px; } -.testimonial-nav { - align-items: center; - background: #ffffff; - border: 1px solid #dce4ec; - border-radius: 50%; - color: #526171; - display: grid; - font-size: 24px; - height: 34px; - place-items: center; - position: absolute; - top: 50%; - transform: translateY(-50%); - width: 34px; -} - -.testimonial-nav.prev { - left: -18px; -} - -.testimonial-nav.next { - right: -18px; -} - -.testimonial-dots { - display: flex; - gap: 8px; - justify-content: center; - margin-top: 12px; -} - -.testimonial-dots span { - background: #14223a; - border-radius: 999px; - height: 6px; - opacity: 0.35; - width: 6px; -} - -.testimonial-dots span:first-child { - opacity: 1; - width: 18px; -} - .sell-bottom-cta { align-items: center; background: linear-gradient(90deg, #f8fffb 0%, #effaf4 100%); @@ -12705,9 +12661,6 @@ a.city-card:hover { grid-template-columns: 1fr; } - .testimonial-nav { - display: none; - } .services-search, .service-mini-search { @@ -35193,3 +35146,90 @@ a.listing-detail-secondary { color: #0b9f5c; font-weight: 900; } + +/* Zapowiedziane funkcje: plakietka "Wkrotce" i nieaktywny przycisk obok niej. */ +.soon-tag { + background: #eef2f7; + border-radius: 999px; + color: #56657a; + font-size: 10px; + font-style: normal; + font-weight: 900; + letter-spacing: 0.02em; + padding: 3px 8px; + text-transform: uppercase; + white-space: nowrap; +} + +.ai-card button:disabled, +.map-ai-card button:disabled, +.account-premium-card button:disabled { + cursor: not-allowed; + opacity: 0.55; +} + +.tour-card .soon-tag { + margin-left: auto; +} + +/* Szybkie poradniki i wyszukiwarka poradnikow prowadza do prawdziwych stron. */ +.quick-guides-card :is(a, article) { + color: inherit; + text-decoration: none; +} + +.quick-guides-card > a:last-child { + align-items: center; + color: #0b9f5c; + display: inline-flex; + font-size: 13px; + font-weight: 900; + gap: 8px; + padding-top: 14px; + text-decoration: none; +} + +.guide-topic-head a { + color: #0b9f5c; + font-size: 13px; + font-weight: 900; + text-decoration: none; +} + +.guides-search-empty { + color: #526171; + font-size: 14px; +} + +/* Zawezenie listy do ofert widocznych na mapie. */ +.map-area-note { + align-items: center; + background: #f1f8f4; + border: 1px solid #cfe8db; + border-radius: 10px; + color: #27364d; + display: flex; + font-size: 13px; + font-weight: 800; + gap: 8px; + margin: 0 0 14px; + padding: 10px 14px; +} + +.map-area-note button { + background: transparent; + border: 0; + color: #0b9f5c; + cursor: pointer; + font-size: 13px; + font-weight: 900; + margin-left: auto; + padding: 0; +} + +.comparison-share-info { + color: #0b9f5c; + font-size: 13px; + font-weight: 900; + margin: 0 0 12px; +} diff --git a/frontend/tests/routing.spec.ts b/frontend/tests/routing.spec.ts index 364110a..994a4d3 100644 --- a/frontend/tests/routing.spec.ts +++ b/frontend/tests/routing.spec.ts @@ -458,3 +458,43 @@ test.describe('Negocjacje', () => { await expect(page.getByText('Nie znaleźliśmy tego ogłoszenia')).toBeVisible(); }); }); + +test.describe('Standard: przyciski robia to, co obiecuja', () => { + test('wyszukiwarka poradnikow trzyma fraze w adresie i przezywa F5', async ({ page }) => { + await goto(page, ROUTES.guides); + await page.locator('.guides-search input').fill('kredyt'); + await page.locator('.guides-search button').click(); + await page.waitForFunction(() => window.location.search.includes('szukaj=kredyt')); + await page.reload(); + await expect(page.locator('section[aria-label="Wyniki wyszukiwania"]')).toContainText('kredyt'); + }); + + test('"Szukaj na biezacej mapie" zaweza liste do ofert z mapy', async ({ page }) => { + await goto(page, ROUTES.buy); + await page.locator('.map-card').first().waitFor(); + await page.getByRole('button', { name: /Szukaj na bieżącej mapie/ }).first().click(); + await page.waitForFunction(() => window.location.search.includes('obszar=')); + await expect(page.locator('.map-area-note')).toBeVisible(); + await page.locator('.map-area-note button').click(); + await page.waitForFunction(() => !window.location.search.includes('obszar=')); + }); + + test('porownanie trzyma wybrane oferty w adresie', async ({ page }) => { + await login(page); + await goto(page, ROUTES.buy); + await page.locator('.real-result-card').first().waitFor(); + const href = await page.locator('.real-result-card .card-stretched-link').first().getAttribute('href'); + const listingId = Number(href!.split('/').pop()); + await goto(page, `${ROUTES.comparison}?oferty=${listingId}`); + await expect(page.locator('.comparison-main')).toContainText('Zobacz ogłoszenie'); + await page.reload(); + await expect(page.locator('.comparison-main')).toContainText('Zobacz ogłoszenie'); + }); + + test('kanaly kontaktu w pomocy to prawdziwe linki mailto i tel', async ({ page }) => { + await login(page); + await goto(page, ROUTES.accountHelpContact); + await expect(page.locator('a.help-contact-channel-action[href^="mailto:"]')).toHaveCount(1); + await expect(page.locator('a.help-contact-channel-action[href^="tel:"]')).toHaveCount(1); + }); +});