Widget Listy Sklepów Medycznych

Kompletna dokumentacja integracji kompaktowego widget'a listy sklepów medycznych NFZ - idealnego rozwiązania dla sidebara, dashboardów i aplikacji mobilnych

Przegląd Widget'a Listy

Widget listy to kompaktowe rozwiązanie JavaScript wyświetlające uporządkowaną listę najbliższych sklepów medycznych NFZ. Idealny jako uzupełnienie widget'a mapy lub samodzielne rozwiązanie dla przestrzeni o ograniczonej powierzchni.

Główne zalety:

  • Minimalistyczny design: Zajmuje mało miejsca, doskonały dla sidebara
  • Brak zależności: Nie wymaga dodatkowych bibliotek jak Leaflet
  • Mobile-first: Zoptymalizowany dla urządzeń mobilnych
  • Sortowanie automatyczne: Sklepy sortowane według odległości
  • Akcje użytkownika: Kopiowanie adresu, nawigacja, kontakt

Funkcjonalności Widget'a

Sortowanie wg Odległości

Automatyczne sortowanie sklepów od najbliższych do najdalszych z wyświetlaniem precyzyjnej odległości w km.

Pełne Informacje

Nazwa sklepu, pełny adres, numer telefonu, godziny otwarcia oraz dostępne zakresy świadczeń NFZ.

Interaktywne Akcje

Jednym kliknięciem: kopiowanie adresu, otwieranie nawigacji GPS, dzwonienie lub wysyłanie email.

Responsywny Design

Automatyczne dostosowanie układu do rozmiaru ekranu z zachowaniem czytelności na wszystkich urządzeniach.

Filtrowanie NFZ

Możliwość filtrowania według konkretnego zakresu świadczeń: aparaty słuchowe, ortopedia, środki pomocnicze.

Motywy Kolorystyczne

4 gotowe motywy dostosowane do różnych stylów stron: Default, Medical, Light i Dark.

Demonstracja na Żywo

Przetestuj widget listy w działaniu. Wybierz motyw kolorystyczny i zobacz jak prezentuje się lista sklepów medycznych.

Wybierz motyw:

Default

Standardowy motyw eZWM

Medical

Motyw medyczny

Light

Jasny motyw

Dark

Ciemny motyw

Uwaga: Demo spróbuje pobrać Twoją lokalizację. W przypadku odmowy użyje losowego miasta w Polsce.

Przewodnik Integracji

Szybka integracja: Widget listy nie wymaga dodatkowych bibliotek i można go zintegrować w zaledwie 3 krokach!

Załaduj eZWM Shops Loader

W przeciwieństwie do widget'a mapy, lista sklepów nie wymaga biblioteki Leaflet. Wystarczy jeden skrypt:

<-- Dodaj przed zamknięciem </body> -->
<script src="https://ecommerce.ezwm.pl/widgets/ezwm-shops-loader.js"></script>
Skrypt automatycznie wykrywa środowisko i dostosowuje endpoint API. Obsługuje cache'owanie i optymalizacje wydajności.

Przygotuj Kontener HTML

Utwórz element HTML, w którym zostanie wyrenderowana lista sklepów:

<div id="medical-shops-list" style="width: 100%; height: 400px; overflow-y: auto;">
    <!-- Loader podczas ładowania -->
    <div class="shops-loading" style="display: flex; align-items: center; justify-content: center; height: 100%; background: #f8f9fa;">
        <i class="fas fa-spinner fa-spin fa-2x text-primary"></i>
        <span class="ms-2">Ładowanie sklepów...</span>
    </div>
</div>
Ważne: Określ wysokość kontenera dla prawidłowego przewijania. Zalecana minimalna wysokość to 300px.

Inicjalizuj Widget

Wywołaj metodę ładowania listy z parametrami konfiguracyjnymi:

<script>
// Podstawowa inicjalizacja
EZWMShopsLoader.loadShopsList('medical-shops-list', {
    latitude: 50.0647,   // Kraków
    longitude: 19.9449,
    theme: 'default',
    promieniWyszukiwania: 20,  // km
    limitSklepow: 10
});

// Zaawansowana inicjalizacja z geolokalizacją
document.addEventListener('DOMContentLoaded', function() {
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(
            function(position) {
                // Sukces - użyj lokalizacji użytkownika
                EZWMShopsLoader.loadShopsList('medical-shops-list', {
                    latitude: position.coords.latitude,
                    longitude: position.coords.longitude,
                    theme: 'medical',
                    zakresSwiadczenia: 'PO',  // tylko produkty ortopedyczne
                    promieniWyszukiwania: 30,
                    limitSklepow: 8
                });
            },
            function(error) {
                // Fallback dla błędów geolokalizacji
                console.warn('Geolocation error:', error);
                EZWMShopsLoader.loadShopsList('medical-shops-list', {
                    latitude: 52.2297,   // Warszawa jako backup
                    longitude: 21.0122,
                    theme: 'light',
                    promieniWyszukiwania: 25,
                    limitSklepow: 12
                });
            },
            { timeout: 5000, enableHighAccuracy: false }
        );
    } else {
        // Brak obsługi geolokalizacji
        EZWMShopsLoader.loadShopsList('medical-shops-list', {
            latitude: 50.0647,
            longitude: 19.9449
        });
    }
});
</script>

Opcje Konfiguracji

Parametr Typ Domyślnie Opis Przykład
latitude number wymagane Szerokość geograficzna punktu wyszukiwania (-90 do 90) 50.0647
longitude number wymagane Długość geograficzna punktu wyszukiwania (-180 do 180) 19.9449
theme string 'default' Motyw kolorystyczny: 'default', 'medical', 'light', 'dark' 'medical'
promieniWyszukiwania number 20 Promień wyszukiwania w kilometrach (1-100) 30
limitSklepow number 10 Maksymalna liczba sklepów do wyświetlenia (1-50) 15
zakresSwiadczenia string|null null Filtr zakresu NFZ: 'AS', 'PO', 'SP', 'SO' lub null (wszystkie) 'AS'
showDistance boolean true Czy wyświetlać odległość do sklepu false
showPhone boolean true Czy wyświetlać numer telefonu false
enableActions boolean true Czy włączyć akcje użytkownika (nawigacja, kopiowanie) false

Zakresy Świadczeń NFZ

Platforma obsługuje wszystkie główne zakresy świadczeń medycznych refundowanych przez NFZ. Każdy sklep może oferować jeden lub więcej zakresów.

AS Aparaty Słuchowe

Przykładowe produkty:

  • Aparaty słuchowe zauszne
  • Aparaty słuchowe douszne
  • Aparaty słuchowe wszczepiane
  • Akcesoria do aparatów słuchowych

PO Przedmioty Ortopedyczne

Przykładowe produkty:

  • Buty ortopedyczne
  • Wkładki ortopedyczne
  • Ortezy kończyn
  • Protezy kończyn

SP Środki Pomocnicze

Przykładowe produkty:

  • Wózki inwalidzkie
  • Kule i laski
  • Chodziki i balkoniki
  • Sprzęt rehabilitacyjny

SO Szkła Okularowe

Przykładowe produkty:

  • Szkła okularowe korekcyjne
  • Szkła progresywne
  • Szkła specjalistyczne
  • Oprawy okularowe
Wskazówka: Pozostaw parametr zakresSwiadczenia jako null aby wyświetlić wszystkie sklepy niezależnie od oferowanych zakresów.

Przykłady Zastosowań

Sidebar na Stronie Medycznej

Kompaktowa lista sklepów w sidebarze strony internetowej placówki medycznej lub apteki. Pacjenci mogą szybko znaleźć najbliższe punkty sprzedaży wyrobów medycznych.

Zalecana konfiguracja: limitSklepow: 5-8, theme: 'medical'

Dashboard Administratora

Panel administracyjny systemu CRM z szybkim podglądem partnerów handlowych w okolicy. Możliwość filtrowania według zakresu współpracy.

Zalecana konfiguracja: enableActions: true, showDistance: true

Aplikacja Mobilna

Lista sklepów w aplikacji mobilnej dla pacjentów. Optymalizowana dla małych ekranów z intuicyjnymi akcjami dotyk.

Zalecana konfiguracja: theme: 'light', limitSklepow: 10

Uzupełnienie Widget'a Mapy

Lista szczegółów jako uzupełnienie interaktywnej mapy. Użytkownicy mogą przeglądać informacje o sklepach w wygodnej formie tekstowej.

Zalecana konfiguracja: synchronizacja z mapą przez JavaScript

Wersja do Druku

Lista sklepów przygotowana do wydruku dla pacjentów. Czytelny format z wszystkimi niezbędnymi informacjami kontaktowymi.

Zalecana konfiguracja: theme: 'light', showPhone: true

Newsletter i Email

Osadzenie listy sklepów in newsletterach lub automatycznych emailach dla pacjentów. Możliwość personalizacji według lokalizacji odbiorcy.

Zalecana konfiguracja: enableActions: false, podstawowe informacje

Przykłady Zaawansowanej Integracji

Przykład 1: Widget z dynamicznym filtrowaniem

<div class="filters-container mb-3">
    <select id="scope-filter" class="form-select">
        <option value="">Wszystkie zakresy NFZ</option>
        <option value="AS">Aparaty słuchowe</option>
        <option value="PO">Produkty ortopedyczne</option>
        <option value="SP">Środki pomocnicze</option>
        <option value="SO">Szkła okularowe</option>
    </select>
    <input type="range" id="radius-slider" min="5" max="100" value="20" class="form-range">
    <span id="radius-display">20 km</span>
</div>
<div id="dynamic-shops-list" style="height: 500px;"></div>

<script>
const baseConfig = {
    latitude: 50.0647,
    longitude: 19.9449,
    theme: 'medical'
};

let currentConfig = { ...baseConfig };

// Funkcja odświeżania listy
function refreshShopsList() {
    EZWMShopsLoader.loadShopsList('dynamic-shops-list', currentConfig);
}

// Obsługa zmiany zakresu NFZ
document.getElementById('scope-filter').addEventListener('change', function(e) {
    currentConfig.zakresSwiadczenia = e.target.value || null;
    refreshShopsList();
});

// Obsługa zmiany promienia
document.getElementById('radius-slider').addEventListener('input', function(e) {
    const radius = parseInt(e.target.value);
    currentConfig.promieniWyszukiwania = radius;
    document.getElementById('radius-display').textContent = radius + ' km';
    
    // Debounce dla lepszej wydajności
    clearTimeout(window.radiusTimeout);
    window.radiusTimeout = setTimeout(refreshShopsList, 500);
});

// Inicjalizacja
refreshShopsList();
</script>

Przykład 2: Synchronizacja z widget'em mapy

<div class="row">
    <div class="col-md-8">
        <div id="synchronized-map" style="height: 400px;"></div>
    </div>
    <div class="col-md-4">
        <div id="synchronized-list" style="height: 400px;"></div>
    </div>
</div>

<script>
const syncConfig = {
    latitude: 50.0647,
    longitude: 19.9449,
    theme: 'medical',
    promieniWyszukiwania: 25,
    limitSklepow: 15
};

// Załaduj oba widgety z tą samą konfiguracją
Promise.all([
    EZWMMapLoader.loadMap('synchronized-map', syncConfig),
    EZWMShopsLoader.loadShopsList('synchronized-list', syncConfig)
]).then(() => {
    console.log('Oba widgety zostały załadowane i zsynchronizowane');
});

// Funkcja do aktualizacji obu widgetów jednocześnie
function updateBothWidgets(newConfig) {
    const finalConfig = { ...syncConfig, ...newConfig };
    
    EZWMMapLoader.loadMap('synchronized-map', finalConfig);
    EZWMShopsLoader.loadShopsList('synchronized-list', finalConfig);
}

// Przykład użycia - zmiana lokalizacji dla obu widgetów
function changeLocation(lat, lng) {
    updateBothWidgets({
        latitude: lat,
        longitude: lng
    });
}
</script>

Przykład 3: Widget z cache'owaniem i optymalizacją

<div id="cached-shops-list" style="height: 400px;"></div>
<button id="refresh-btn" class="btn btn-primary mt-2">Odśwież dane</button>

<script>
class ShopsListManager {
    constructor(containerId) {
        this.containerId = containerId;
        this.cache = new Map();
        this.cacheTimeout = 5 * 60 * 1000; // 5 minut
    }
    
    generateCacheKey(config) {
        return JSON.stringify({
            lat: config.latitude.toFixed(4),
            lng: config.longitude.toFixed(4),
            radius: config.promieniWyszukiwania,
            scope: config.zakresSwiadczenia,
            limit: config.limitSklepow
        });
    }
    
    async loadShops(config) {
        const cacheKey = this.generateCacheKey(config);
        const cached = this.cache.get(cacheKey);
        
        // Sprawdź cache
        if (cached && (Date.now() - cached.timestamp) < this.cacheTimeout) {
            console.log('Używam danych z cache');
            return cached.success;
        }
        
        // Załaduj świeże dane
        console.log('Ładuję świeże dane...');
        const success = await EZWMShopsLoader.loadShopsList(this.containerId, config);
        
        // Zapisz w cache
        this.cache.set(cacheKey, {
            success: success,
            timestamp: Date.now()
        });
        
        return success;
    }
    
    clearCache() {
        this.cache.clear();
        console.log('Cache wyczyszczony');
    }
}

// Użycie
const shopsManager = new ShopsListManager('cached-shops-list');

const config = {
    latitude: 50.0647,
    longitude: 19.9449,
    theme: 'default',
    promieniWyszukiwania: 20,
    limitSklepow: 12
};

// Załaduj dane (z cache lub świeże)
shopsManager.loadShops(config);

// Przycisk odświeżania
document.getElementById('refresh-btn').addEventListener('click', function() {
    shopsManager.clearCache();
    shopsManager.loadShops(config);
});
</script>