# Player

Player VirtualCar360 to gotowy wizualny komponent przeznaczony do osadzania na stronach internetowych. Player działa jako zewnętrzny widget ładowany przez `iframe`, dzięki czemu nie wymaga implementowania własnej galerii zdjęć, obsługi hotspotów, powiększania zdjęć ani logiki pobierania najnowszej galerii pojazdu.

div
iframe
Player może być wykorzystywany między innymi:

- na listingu ofert,
- jako główny slider na stronie pojazdu,
- jako dodatkowy element opisu pojazdu,
- jako interaktywna galeria zdjęć,
- jako element prezentujący zdjęcia, hotspoty, certyfikat pojazdu oraz inne oferty z tej samej lokalizacji.


Player może zostać załadowany na podstawie **carId** lub  **numeru VIN** albo **numeru rejestracyjnego** pojazdu. Po przekazaniu identyfikatora pojazdu Player automatycznie wyszukuje najnowszą dostępną galerię i wyświetla ją użytkownikowi.

`carId` jest wewnętrznym identyfikatorem Playera i pozwala precyzyjnie wskazać konkretną prezentację pojazdu. W praktycznych integracjach wygodniejsze może być jednak użycie `vin` albo `numberplates`, ponieważ te wartości łatwiej powiązać z ofertą w systemie dealera, CRM lub na stronie internetowej. W takim przypadku system automatycznie wyszukuje i wyświetla najnowszego Playera dostępnego dla danego pojazdu. 

## Zasada działania

Player jest osadzany jako `iframe` wskazujący na adres:

```txt
https://virtualcar360.pl/player/
```

Do adresu należy przekazać wymagane parametry w query stringu.

Minimalna konfiguracja wymaga:

- identyfikatora pojazdu: `carId` lub `vin` albo `numberplates`,
- klucza API: `key`.


Player po załadowaniu:

1. odczytuje przekazane parametry z adresu URL,
2. identyfikuje pojazd po numerze VIN albo numerze rejestracyjnym,
3. pobiera najnowszą galerię przypisaną do pojazdu,
4. renderuje zdjęcia, dostępne zestawy zdjęć, hotspoty i dodatkowe elementy prezentacji,
5. umożliwia użytkownikowi przeglądanie oraz powiększanie zdjęć.


## Parametry URL

| Parametr           | Wymagany | Opis |
|  --- | --- | --- |
| `carId` | warunkowo | Identyfikator samochodu. Pozwala bezpośrednio wskazać konkretny player. |
| `vin` | warunkowo | Numer VIN pojazdu. Wymagany, jeżeli nie przekazano `carId` lub `numberplates`. |
| `numberplates` | warunkowo | Numer rejestracyjny pojazdu. Wymagany, jeżeli nie przekazano `carId` lub `vin`. |
| `key` | tak | Klucz API przypisany do lokalizacji albo klucz grupowy dla wielu lokalizacji. |


W jednym adresie Playera należy przekazać tylko jeden identyfikator pojazdu: `carId`, `vin` albo `numberplates`. Nie ma potrzeby przekazywania kilku parametrów jednocześnie. `carId` pozwala wskazać konkretny Player, natomiast `vin` i `numberplates` służą do automatycznego wyszukania najnowszego Playera dostępnego dla danego pojazdu. 

## Osadzenie Playera po numerze VIN

```html
<iframe
  src="https://virtualcar360.pl/player/?vin=1NKCLR0X1XR568641&key=TWOJ_KLUCZ_API"
  width="100%"
  height="600"
  frameborder="0"
  allowfullscreen
></iframe>
```

## Osadzenie Playera po numerze rejestracyjnym

```html
<iframe
  src="https://virtualcar360.pl/player/?numberplates=WW4433E&key=TWOJ_KLUCZ_API"
  width="100%"
  height="600"
  frameborder="0"
  allowfullscreen
></iframe>
```

## Responsywne osadzenie

Zalecanym sposobem osadzania Playera jest umieszczenie `iframe` w responsywnym kontenerze. Dzięki temu Player dopasowuje się do szerokości strony i zachowuje proporcje niezależnie od urządzenia.

```html
<div class="vc360-player-wrapper">
  <iframe
    src="https://virtualcar360.pl/player/?vin=1NKCLR0X1XR568641&key=TWOJ_KLUCZ_API"
    title="VirtualCar360 Player"
    frameborder="0"
    allowfullscreen
    loading="lazy"
  ></iframe>
</div>
```

```css
.vc360-player-wrapper {
  position: relative;
  width: 100%;
  padding-bottom: 56.25%;
  height: 0;
  overflow: hidden;
}

.vc360-player-wrapper iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
```

Proporcja `56.25%` odpowiada układowi `16:9`. Jeżeli Player ma być wyższy, na przykład jako główny slider strony pojazdu, można zastosować inną proporcję lub ustawić stałą wysokość kontenera.

Przykład dla większego Playera na stronie szczegółów pojazdu:

```css
.vc360-player-wrapper {
  position: relative;
  width: 100%;
  height: 720px;
  overflow: hidden;
}

.vc360-player-wrapper iframe {
  width: 100%;
  height: 100%;
  border: 0;
}
```

## Przykład użycia na listingu ofert

Player może być osadzony bezpośrednio na karcie oferty, jeżeli listing ma prezentować interaktywną galerię zamiast statycznego zdjęcia.

```html
<article class="vehicle-card">
  <h2>Skoda Octavia 2.0 TDI</h2>

  <div class="vehicle-card__media">
    <iframe
      src="https://virtualcar360.pl/player/?vin=TMBJC7NE8J0123456&key=TWOJ_KLUCZ_API"
      title="Galeria VirtualCar360"
      frameborder="0"
      allowfullscreen
      loading="lazy"
    ></iframe>
  </div>

  <div class="vehicle-card__content">
    <p>Rok produkcji: 2021</p>
    <p>Przebieg: 84 000 km</p>
    <a href="/oferta/skoda-octavia-tmbjc7ne8j0123456">
      Zobacz szczegóły
    </a>
  </div>
</article>
```

```css
.vehicle-card__media {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: #f5f5f5;
  overflow: hidden;
}

.vehicle-card__media iframe {
  width: 100%;
  height: 100%;
  border: 0;
}
```

Na listingu ofert warto używać atrybutu `loading="lazy"`, aby Player ładował się dopiero wtedy, gdy karta pojazdu znajdzie się w obszarze widocznym dla użytkownika. Takie podejście ogranicza liczbę jednocześnie ładowanych Playerów i poprawia wydajność strony. 

## Przykład użycia jako slider na stronie pojazdu

Player może pełnić funkcję głównego slidera na stronie szczegółów pojazdu. W takim scenariuszu zastępuje klasyczną galerię zdjęć i zapewnia użytkownikowi dostęp do zdjęć, powiększeń, hotspotów oraz dodatkowych materiałów.

```html
<section class="vehicle-hero">
  <div class="vehicle-hero__player">
    <iframe
      src="https://virtualcar360.pl/player/?numberplates=WW4433E&key=TWOJ_KLUCZ_API"
      title="Prezentacja pojazdu VirtualCar360"
      frameborder="0"
      allowfullscreen
    ></iframe>
  </div>

  <div class="vehicle-hero__summary">
    <h1>Volkswagen Passat Variant</h1>
    <p>2.0 TDI · DSG · 2022</p>
  </div>
</section>
```

```css
.vehicle-hero__player {
  width: 100%;
  height: 680px;
}

.vehicle-hero__player iframe {
  width: 100%;
  height: 100%;
  border: 0;
}
```

## Dynamiczne generowanie adresu Playera

W typowej integracji strona klienta posiada już dane pojazdu, na przykład VIN albo numer rejestracyjny. Adres Playera można wtedy wygenerować dynamicznie.

```js
function createVirtualCarPlayerUrl({ vin, numberplates, apiKey }) {
  const url = new URL('https://virtualcar360.pl/player/');

  if (vin) {
    url.searchParams.set('vin', vin);
  } else if (numberplates) {
    url.searchParams.set('numberplates', numberplates);
  } else {
    throw new Error('VIN albo numer rejestracyjny jest wymagany.');
  }

  url.searchParams.set('key', apiKey);

  return url.toString();
}

const playerUrl = createVirtualCarPlayerUrl({
  vin: '1NKCLR0X1XR568641',
  apiKey: 'TWOJ_KLUCZ_API',
});

document.querySelector('#vc360-player').src = playerUrl;
```

```html
<iframe
  id="vc360-player"
  title="VirtualCar360 Player"
  width="100%"
  height="600"
  frameborder="0"
  allowfullscreen
></iframe>
```

## Przykład integracji w React

```tsx
type VirtualCarPlayerProps = {
  vin?: string;
  numberplates?: string;
  apiKey: string;
};

export function VirtualCarPlayer({
  vin,
  numberplates,
  apiKey,
}: VirtualCarPlayerProps) {
  const url = new URL('https://virtualcar360.pl/player/');

  if (vin) {
    url.searchParams.set('vin', vin);
  } else if (numberplates) {
    url.searchParams.set('numberplates', numberplates);
  } else {
    throw new Error('VIN albo numer rejestracyjny jest wymagany.');
  }

  url.searchParams.set('key', apiKey);

  return (
    <iframe
      src={url.toString()}
      title="VirtualCar360 Player"
      width="100%"
      height="600"
      frameBorder="0"
      allowFullScreen
      loading="lazy"
    />
  );
}
```

## Przykład integracji w Angularze

```ts
import { CommonModule } from '@angular/common';
import { Component, Input } from '@angular/core';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';

@Component({
  selector: 'vc360-player',
  standalone: true,
  imports: [CommonModule],
  template: `
    <iframe
      *ngIf="playerUrl"
      [src]="playerUrl"
      title="VirtualCar360 Player"
      width="100%"
      height="600"
      frameborder="0"
      allowfullscreen
      loading="lazy"
    ></iframe>
  `,
})
export class VirtualCarPlayerComponent {
  @Input() carId?: string | number;
  @Input() vin?: string;
  @Input() numberplates?: string;
  @Input({ required: true }) apiKey!: string;

  constructor(private readonly sanitizer: DomSanitizer) {}

  get playerUrl(): SafeResourceUrl | null {
    const url = new URL('https://virtualcar360.pl/player/');

    if (this.carId) {
      url.searchParams.set('carId', String(this.carId));
    } else if (this.vin) {
      url.searchParams.set('vin', this.vin);
    } else if (this.numberplates) {
      url.searchParams.set('numberplates', this.numberplates);
    } else {
      return null;
    }

    url.searchParams.set('key', this.apiKey);

    return this.sanitizer.bypassSecurityTrustResourceUrl(url.toString());
  }
}
```

Przykład użycia komponentu:

```ts
<vc360-player
  [vin]="vehicle.vin"
  [apiKey]="virtualCarApiKey"
></vc360-player>
```

albo po numerze rejestracyjnym:

```ts
<vc360-player
  [numberplates]="vehicle.numberPlates"
  [apiKey]="virtualCarApiKey"
></vc360-player>
```

albo po carId:

```ts
<vc360-player
  [carId]="vehicle.virtualCarPlayerId"
  [apiKey]="virtualCarApiKey"
></vc360-player>
```

## Prezentowane dane

Zakres danych widocznych w Playerze zależy od tego, jakie materiały są dostępne dla danej galerii pojazdu.

Player może prezentować między innymi:

- zdjęcia samochodu z zamkniętymi drzwiami,
- zdjęcia samochodu z otwartymi drzwiami,
- zdjęcia dodatkowe,
- panoramę wnętrza,
- interaktywne zdjęcie wykonane z gimbala,
- hotspoty,
- certyfikat samochodu,
- inne oferty z tej samej lokalizacji.


Jeżeli dana galeria nie zawiera określonego typu materiału, Player może go pominąć i wyświetlić pozostałe dostępne dane.

## Hotspoty w Playerze

Hotspoty są częścią Playera i służą do oznaczania konkretnych elementów bezpośrednio na zdjęciach samochodu. Hotspot może wskazywać na przykład:

- reflektor,
- felgę,
- element wyposażenia,
- rysę,
- uszkodzenie,
- detal karoserii,
- element wnętrza.


Hotspot może posiadać dodatkowe zdjęcia pokazujące zaznaczony element w większym zbliżeniu. Przykładowo, jeżeli hotspot wskazuje reflektor, po jego wybraniu użytkownik może zobaczyć dodatkowe zdjęcie reflektora. Jeżeli hotspot oznacza rysę na karoserii, Player może wyświetlić powiększone zdjęcie tego miejsca.

Dzięki hotspotom Player może pełnić funkcję interaktywnej prezentacji stanu pojazdu, a nie tylko standardowej galerii zdjęć.

## Automatyczny wybór galerii

Player automatycznie wybiera najnowszą galerię przypisaną do przekazanego numeru VIN albo numeru rejestracyjnego.

Oznacza to, że w integracji nie trzeba znać identyfikatora `carId`. Wystarczy, że system klienta posiada VIN albo numer rejestracyjny pojazdu.

Przykład:

```txt
https://virtualcar360.pl/player/?vin=1NKCLR0X1XR568641&key=TWOJ_KLUCZ_API
```

W tym przypadku Player:

1. wyszuka galerie przypisane do VIN `1NKCLR0X1XR568641`,
2. wybierze najnowszą galerię,
3. wyświetli ją w osadzonym widoku.


## Player a API

Player jest najprostszym sposobem integracji, ponieważ nie wymaga samodzielnego pobierania zdjęć ani implementowania logiki galerii po stronie klienta.

Jeżeli chcesz samodzielnie zbudować własny interfejs galerii, użyj API. Typowy proces API wygląda wtedy następująco:

1. Pobierz najnowszą galerię po VIN albo numerze rejestracyjnym.
2. Odczytaj `id` galerii.
3. Przekaż `id` jako `carId` do endpointu `/image-set`.
4. Pobierz zestawy zdjęć, hotspoty i linki do materiałów video.
5. Zbuduj własny interfejs prezentacji pojazdu.


W przypadku Playera ten proces jest obsługiwany automatycznie.

## Bezpieczeństwo i dobre praktyki

- Używaj klucza API przypisanego do właściwej lokalizacji albo klucza grupowego, jeżeli Player ma obsługiwać wiele lokalizacji.
- Nie zapisuj prawdziwych kluczy API w publicznych repozytoriach.
- Dla wielu Playerów na jednej stronie stosuj `loading="lazy"`.
- Na listingu ofert unikaj jednoczesnego ładowania zbyt wielu Playerów widocznych od razu po wejściu na stronę.
- Dla stron szczegółów pojazdu zalecane jest użycie Playera jako głównego elementu multimedialnego.
- Dla widoków mobilnych ustaw szerokość `iframe` na `100%` i kontroluj wysokość przez responsywny kontener.


## Najczęstsze problemy

### Player nie wyświetla galerii

Sprawdź, czy:

- przekazano poprawny `vin` albo `numberplates`,
- przekazano poprawny `key`,
- pojazd posiada galerię w systemie VirtualCar360,
- klucz API ma dostęp do lokalizacji, w której znajduje się pojazd.


### Player pokazuje inną galerię niż oczekiwano

Player automatycznie wybiera najnowszą galerię dla danego pojazdu. Jeżeli pojazd posiada wiele galerii, wyświetlona zostanie najnowsza dostępna galeria.

### Player nie dopasowuje się do szerokości strony

Upewnij się, że `iframe` znajduje się w responsywnym kontenerze i ma ustawione:

```css
width: 100%;
height: 100%;
border: 0;
```

### Na stronie ładuje się zbyt wiele Playerów

Na listingu ofert dodaj `loading="lazy"` i rozważ ładowanie Playera dopiero po wejściu karty pojazdu w obszar widoczny użytkownika.

## Minimalny przykład produkcyjny

```html
<div class="vc360-player-wrapper">
  <iframe
    src="https://virtualcar360.pl/player/?vin=1NKCLR0X1XR568641&key=TWOJ_KLUCZ_API"
    title="VirtualCar360 Player"
    frameborder="0"
    allowfullscreen
    loading="lazy"
  ></iframe>
</div>
```

```css
.vc360-player-wrapper {
  position: relative;
  width: 100%;
  padding-bottom: 56.25%;
  height: 0;
  overflow: hidden;
}

.vc360-player-wrapper iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}
```