d655bcc9b1
Deploy Polska Lokalnie / deploy (push) Successful in 11s
Strony pokazywaly zmyslone dane jako prawdziwe. Usuwam je i zostawiam puste stany tam, gdzie funkcja nie ma jeszcze zrodla danych: - strona glowna: 4 fikcyjne "Polecane ogloszenia" (pokazywane przy mniej niz 4 ogloszeniach) - teraz prawdziwe ogloszenia albo pusty stan; - mapa: zapasowe fikcyjne oferty kupna i wynajmu; - wyszukiwarka: gotowe wpisy "Ostatnio wyszukiwane"; - negocjacje: zmyslona "szansa na zakup" i "podobne transakcje" - pusty stan; - historia cen: wykres i statystyki z generatora - puste do czasu podpiecia API; - alerty cenowe: wykres z generatora; srednia liczona tylko z ogloszen. Wczesniej przy braku ogloszen podstawiana byla stawka szacunkowa, przez co monitoring w tle zglaszal nieistniejace zmiany cen; - spotkania: przykladowe i "testowe" spotkania dopisywane kazdemu kontu, takze odfiltrowane z localStorage; - wiadomosci: 7 fikcyjnych rozmow; pusty stan zamiast bledu bez watkow; - moje oferty: 12 ukrytych fikcyjnych ofert zapisywanych w localStorage; - poradniki: zmyslone polecane artykuly (teraz najczesciej czytane z API) i liczniki "5 120 ofert"; - wycena: wskaznik "% dokladnosci" liczony z liczby wypelnionych pol; - martwy kod z fikcyjnymi powiadomieniami, znacznikami mapy i statystykami. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
223 lines
8.0 KiB
TypeScript
223 lines
8.0 KiB
TypeScript
// Centralna mapa adresów aplikacji. Jedyne źródło prawdy dla nawigacji -
|
|
// komponenty korzystają z ROUTES zamiast trzymać identyfikatory widoków w stanie.
|
|
export const ROUTES = {
|
|
home: '/',
|
|
buy: '/kupno',
|
|
rent: '/wynajem',
|
|
sell: '/jak-sprzedawac',
|
|
valuation: '/wycena',
|
|
priceHistory: '/historia-cen',
|
|
districtRanking: '/ranking-dzielnic',
|
|
negotiation: '/negocjacje',
|
|
comparison: '/konto/porownanie',
|
|
add: '/dodaj-ogloszenie',
|
|
edit: '/edytuj-ogloszenie/:id',
|
|
services: '/firmy-i-uslugi',
|
|
companies: '/firmy',
|
|
advertising: '/reklama',
|
|
guides: '/poradniki',
|
|
guideBuying: '/poradniki/kupno-mieszkania',
|
|
guideCredit: '/poradniki/kredyty-hipoteczne',
|
|
guideRent: '/poradniki/wynajem',
|
|
guideInvesting: '/poradniki/inwestowanie',
|
|
guideRenovation: '/poradniki/remont-i-wykonczenie',
|
|
guideLaw: '/poradniki/prawo-i-podatki',
|
|
guideTopicList: '/poradniki/temat/:topicSlug',
|
|
guideArticle: '/poradniki/artykul/:id',
|
|
guideAdd: '/poradniki/dodaj',
|
|
creditCalculator: '/kalkulator-zdolnosci',
|
|
map: '/mapa',
|
|
login: '/logowanie',
|
|
account: '/konto',
|
|
accountSearches: '/konto/wyszukiwania',
|
|
accountPriceAlerts: '/konto/alerty-cenowe',
|
|
accountMeetings: '/konto/spotkania',
|
|
accountListings: '/konto/moje-oferty',
|
|
accountSettings: '/konto/ustawienia',
|
|
accountSecurity: '/konto/bezpieczenstwo',
|
|
accountProfileEdit: '/konto/profil/edycja',
|
|
accountPublicProfile: '/konto/profil',
|
|
accountHelpContact: '/konto/pomoc',
|
|
terms: '/regulamin',
|
|
privacy: '/polityka-prywatnosci',
|
|
activation: '/aktywacja/:token',
|
|
passwordReset: '/reset-hasla/:token',
|
|
notifications: '/powiadomienia',
|
|
favorites: '/ulubione',
|
|
messages: '/wiadomosci',
|
|
admin: '/admin',
|
|
listingDetail: '/oferta/:id',
|
|
publicProfile: '/profil/:id',
|
|
// Ten sam profil pod nazwą użytkownika - adres pokazywany w ustawieniach konta.
|
|
publicProfileByNick: '/u/:nick',
|
|
} as const;
|
|
|
|
export type RoutePath = (typeof ROUTES)[keyof typeof ROUTES];
|
|
|
|
// Kanoniczna lista tematów poradników. Slug = ostatni segment adresu i zarazem klucz w API
|
|
// (/api/articles?topic=slug). `guide` to wbudowany, kompletny poradnik danego tematu.
|
|
export type GuideTopicMeta = { slug: string; title: string; icon: string; guide: string };
|
|
|
|
export const GUIDE_TOPICS: GuideTopicMeta[] = [
|
|
{ slug: 'kupno-mieszkania', title: 'Kupno mieszkania', icon: 'house', guide: ROUTES.guideBuying },
|
|
{ slug: 'kredyty-hipoteczne', title: 'Kredyty hipoteczne', icon: 'percent', guide: ROUTES.guideCredit },
|
|
{ slug: 'wynajem', title: 'Wynajem', icon: 'key', guide: ROUTES.guideRent },
|
|
{ slug: 'inwestowanie', title: 'Inwestowanie', icon: 'chart', guide: ROUTES.guideInvesting },
|
|
{ slug: 'remont-i-wykonczenie', title: 'Remont i wykończenie', icon: 'paint', guide: ROUTES.guideRenovation },
|
|
{ slug: 'prawo-i-podatki', title: 'Prawo i podatki', icon: 'scale', guide: ROUTES.guideLaw },
|
|
];
|
|
|
|
export function guideTopicBySlug(slug: string | undefined): GuideTopicMeta | undefined {
|
|
return GUIDE_TOPICS.find((topic) => topic.slug === slug);
|
|
}
|
|
|
|
// Kafelki tematów na /poradniki prowadzą do listy poradników danego tematu.
|
|
export function guideTopicListPath(slug: string): string {
|
|
return `/poradniki/temat/${slug}`;
|
|
}
|
|
|
|
// Pojedynczy artykuł użytkownika.
|
|
export function articlePath(id: number): string {
|
|
return `/poradniki/artykul/${id}`;
|
|
}
|
|
|
|
// Formularz dodawania artykułu z opcjonalnym wstępnie wybranym tematem.
|
|
export function guideAddPath(topicSlug?: string): string {
|
|
return topicSlug ? `${ROUTES.guideAdd}?temat=${encodeURIComponent(topicSlug)}` : ROUTES.guideAdd;
|
|
}
|
|
|
|
// Szczegóły oferty: identyfikator trafia do adresu, nie do stanu Reacta.
|
|
export function listingPath(id: number): string {
|
|
return `/oferta/${id}`;
|
|
}
|
|
|
|
// Profil publiczny innego użytkownika - otwierany m.in. z rozmowy w wiadomościach.
|
|
export function publicProfilePath(id: number): string {
|
|
return `/profil/${id}`;
|
|
}
|
|
|
|
// Dedykowana strona edycji wlasnego ogloszenia.
|
|
export function listingEditPath(id: number): string {
|
|
return `/edytuj-ogloszenie/${id}`;
|
|
}
|
|
|
|
// Profil pod nazwą użytkownika. Nick jest unikalny w skali serwisu, więc jednoznacznie
|
|
// wskazuje osobę - imię i nazwisko może się powtarzać u wielu kont.
|
|
export function publicProfileNickPath(nick: string): string {
|
|
return `/u/${encodeURIComponent(nick)}`;
|
|
}
|
|
|
|
// Negocjacje dotyczą konkretnej oferty - bez identyfikatora pokazujemy pierwszą z listy.
|
|
export function negotiationPath(offerId?: number | null): string {
|
|
return offerId ? `${ROUTES.negotiation}/${offerId}` : ROUTES.negotiation;
|
|
}
|
|
|
|
// Lista ofert kupna zawężona do miasta - miasto w query stringu, żeby link działał po odświeżeniu
|
|
// i dało się go udostępnić (np. kliknięcie kafelka miasta na stronie głównej).
|
|
export function buyCityPath(city: string): string {
|
|
const params = new URLSearchParams();
|
|
params.set('miasto', city);
|
|
return `${ROUTES.buy}?${params.toString()}`;
|
|
}
|
|
|
|
// Mapa: miasto i typ oferty jako parametry zapytania, dzięki czemu wynik da się udostępnić.
|
|
export function mapPath(city?: string, offerType?: 'SALE' | 'RENT'): string {
|
|
const params = new URLSearchParams();
|
|
if (city) {
|
|
params.set('miasto', city);
|
|
}
|
|
if (offerType === 'RENT') {
|
|
params.set('typ', 'wynajem');
|
|
}
|
|
const query = params.toString();
|
|
return query ? `${ROUTES.map}?${query}` : ROUTES.map;
|
|
}
|
|
|
|
// Historia cen z wybraną lokalizacją w adresie - wejście z alertu cenowego otwiera
|
|
// od razu to miasto, a link da się skopiować, odświeżyć i otworzyć w nowej karcie.
|
|
export function priceHistoryPath(label?: string, propertyType?: string, marketType?: string): string {
|
|
const params = new URLSearchParams();
|
|
if (label) {
|
|
params.set('lokalizacja', label);
|
|
}
|
|
if (propertyType) {
|
|
params.set('typ', propertyType);
|
|
}
|
|
if (marketType) {
|
|
params.set('rynek', marketType);
|
|
}
|
|
const query = params.toString();
|
|
return query ? `${ROUTES.priceHistory}?${query}` : ROUTES.priceHistory;
|
|
}
|
|
|
|
// Lista firm i usług: kategoria w query stringu, dzięki czemu widok da się
|
|
// skopiować, odświeżyć i otworzyć w nowej karcie.
|
|
export function companiesPath(categorySlug?: string): string {
|
|
return categorySlug ? `${ROUTES.companies}?kategoria=${encodeURIComponent(categorySlug)}` : ROUTES.companies;
|
|
}
|
|
|
|
// Strona "Jeszcze nie mamy tej usługi" z formularzem reklamowym. Kategoria trafia do query
|
|
// stringu, żeby po wejściu z kafelka pole "Rodzaj usługi" było już wypełnione.
|
|
export function advertisingPath(categorySlug?: string): string {
|
|
return categorySlug ? `${ROUTES.advertising}?kategoria=${encodeURIComponent(categorySlug)}` : ROUTES.advertising;
|
|
}
|
|
|
|
// Zakładki panelu administratora jako podścieżki /admin/*.
|
|
export const ADMIN_TAB_PATHS = {
|
|
dashboard: '',
|
|
listings: 'ogloszenia',
|
|
users: 'uzytkownicy',
|
|
messages: 'wiadomosci',
|
|
support: 'pomoc-i-kontakt',
|
|
advertisingEnquiries: 'zapytania-o-reklame',
|
|
reports: 'zgloszenia',
|
|
articleRequests: 'poradniki-prosby',
|
|
payments: 'platnosci',
|
|
stats: 'statystyki',
|
|
settings: 'ustawienia',
|
|
moderation: 'weryfikacja',
|
|
categories: 'kategorie',
|
|
locations: 'lokalizacje',
|
|
promotions: 'promocje',
|
|
forbiddenWords: 'zakazane-slowa',
|
|
leads: 'leady',
|
|
campaigns: 'kampanie',
|
|
smtpConfig: 'konfiguracja-smtp',
|
|
smsConfig: 'konfiguracja-sms',
|
|
} as const;
|
|
|
|
export type AdminTabKey = keyof typeof ADMIN_TAB_PATHS;
|
|
|
|
export function adminTabPath(tab: AdminTabKey): string {
|
|
const segment = ADMIN_TAB_PATHS[tab];
|
|
return segment ? `${ROUTES.admin}/${segment}` : ROUTES.admin;
|
|
}
|
|
|
|
export const ADMIN_PATH_TO_TAB = Object.entries(ADMIN_TAB_PATHS).reduce<Record<string, AdminTabKey>>(
|
|
(acc, [tab, segment]) => {
|
|
acc[segment] = tab as AdminTabKey;
|
|
return acc;
|
|
},
|
|
{},
|
|
);
|
|
|
|
// Trasy dostępne wyłącznie po zalogowaniu (bramka w ProtectedRoute).
|
|
export const PROTECTED_PATHS: string[] = [
|
|
ROUTES.add,
|
|
ROUTES.account,
|
|
ROUTES.accountSearches,
|
|
ROUTES.accountPriceAlerts,
|
|
ROUTES.accountMeetings,
|
|
ROUTES.accountListings,
|
|
ROUTES.accountSettings,
|
|
ROUTES.accountSecurity,
|
|
ROUTES.accountProfileEdit,
|
|
ROUTES.accountPublicProfile,
|
|
ROUTES.accountHelpContact,
|
|
ROUTES.notifications,
|
|
ROUTES.favorites,
|
|
ROUTES.messages,
|
|
ROUTES.comparison,
|
|
ROUTES.guideAdd,
|
|
];
|