Řazení Obvodů

master
Kowalski 2026-10-12 16:21:31 +02:00
parent 59322d760f
commit 2e78499bf2
3 changed files with 125 additions and 5 deletions

View File

@ -16,8 +16,22 @@ use Nette\Utils\ArrayHash;
final class ObvodPresenter extends BasePresenter final class ObvodPresenter extends BasePresenter
{ {
private const RAZENI_COOKIE = 'obvodRazeni';
/** @var array<string, string> */
private const RAZENI = [
'cislo-vzestupne' => 'Číslo vzestupně',
'cislo-sestupne' => 'Číslo sestupně',
'rozpracovani-sestupne' => 'Rozpracování sestupně',
'rozpracovani-vzestupne' => 'Rozpracování vzestupně',
'nepropracovani-vzestupne' => 'Nepropracování vzestupně',
'nepropracovani-sestupne' => 'Nepropracování sestupně',
];
private string $skupina = ''; private string $skupina = '';
private string $razeni = 'cislo-vzestupne';
public function __construct( public function __construct(
private ObvodFacade $obvod, private ObvodFacade $obvod,
private ZaznamFacade $zaznam private ZaznamFacade $zaznam
@ -28,7 +42,7 @@ final class ObvodPresenter extends BasePresenter
{ {
} }
public function actionList(?string $skupina = null): void public function actionList(?string $skupina = null, ?string $razeni = null): void
{ {
$this->skupina = $this->obvod->vyberSkupinu( $this->skupina = $this->obvod->vyberSkupinu(
$skupina, $skupina,
@ -37,6 +51,14 @@ final class ObvodPresenter extends BasePresenter
if ($skupina !== null && $skupina === $this->skupina && $this->skupina !== '') { if ($skupina !== null && $skupina === $this->skupina && $this->skupina !== '') {
$this->getHttpResponse()->setCookie(ObvodFacade::SKUPINA_COOKIE, $this->skupina, '+1 year', '/'); $this->getHttpResponse()->setCookie(ObvodFacade::SKUPINA_COOKIE, $this->skupina, '+1 year', '/');
} }
if ($razeni !== null && isset(self::RAZENI[$razeni])) {
$this->razeni = $razeni;
$this->getHttpResponse()->setCookie(self::RAZENI_COOKIE, $razeni, '+1 year', '/');
} else {
$ulozeny = $this->getHttpRequest()->getCookie(self::RAZENI_COOKIE);
$this->razeni = is_string($ulozeny) && isset(self::RAZENI[$ulozeny]) ? $ulozeny : 'cislo-vzestupne';
}
} }
public function renderList(): void public function renderList(): void
@ -45,16 +67,24 @@ final class ObvodPresenter extends BasePresenter
$obvody = []; $obvody = [];
foreach ($this->obvod->getObvody($this->skupina) as $obvod) { foreach ($this->obvod->getObvody($this->skupina) as $obvod) {
$info = $stari[(int) $obvod->CISLO] ?? null; $info = $stari[(int) $obvod->CISLO] ?? null;
$rozpracovan = $info !== null && $info['probiha'];
$obvody[] = (object) [ $obvody[] = (object) [
'ID' => (int) $obvod->ID, 'ID' => (int) $obvod->ID,
'CISLO' => (int) $obvod->CISLO, 'CISLO' => (int) $obvod->CISLO,
'NAZEV' => (string) $obvod->NAZEV, 'NAZEV' => (string) $obvod->NAZEV,
'stav' => $this->stavObvodu($info), 'stav' => $this->stavObvodu($info),
'rozpracovani' => $rozpracovan ? (int) ($info['prideleni'] ?? 0) : null,
'nepropracovani' => !$rozpracovan && $info !== null && $info['mesice'] !== null
? (int) $info['mesice']
: null,
]; ];
} }
$this->seradObvody($obvody);
$this->template->skupina = $this->skupina; $this->template->skupina = $this->skupina;
$this->template->skupiny = $this->obvod->getSkupiny(); $this->template->skupiny = $this->obvod->getSkupiny();
$this->template->razeni = $this->razeni;
$this->template->razeniMoznosti = self::RAZENI;
$this->template->obvody = $obvody; $this->template->obvody = $obvody;
} }
@ -211,6 +241,46 @@ final class ObvodPresenter extends BasePresenter
}); });
} }
/**
* @param list<object> $obvody
*/
private function seradObvody(array &$obvody): void
{
$razeni = $this->razeni;
$sestupne = str_ends_with($razeni, 'sestupne');
$klic = match (true) {
str_starts_with($razeni, 'rozpracovani') => 'rozpracovani',
str_starts_with($razeni, 'nepropracovani') => 'nepropracovani',
default => null,
};
usort($obvody, function (object $a, object $b) use ($sestupne, $klic): int {
if ($klic === null) {
$poradi = $a->CISLO <=> $b->CISLO;
return $sestupne ? -$poradi : $poradi;
}
$prvni = $a->{$klic};
$druhy = $b->{$klic};
if ($prvni === null && $druhy === null) {
return $a->CISLO <=> $b->CISLO;
}
if ($prvni === null) {
return 1;
}
if ($druhy === null) {
return -1;
}
$poradi = $prvni <=> $druhy;
if ($poradi === 0) {
return $a->CISLO <=> $b->CISLO;
}
return $sestupne ? -$poradi : $poradi;
});
}
/** /**
* @param array{mesice: int|null, probiha: bool, prideleni: int|null}|null $info * @param array{mesice: int|null, probiha: bool, prideleni: int|null}|null $info
* @return object{popisek: string, barva: string, text: string} * @return object{popisek: string, barva: string, text: string}

View File

@ -10,8 +10,16 @@
</header> </header>
<section class="panel"> <section class="panel">
<div class="filtry" n:if="$skupiny" role="group" aria-label="Filtr skupin"> <div class="filtry">
<a n:foreach="$skupiny as $s" n:href="list, skupina: $s" n:class="$skupina === $s ? 'tlacitko tlacitko-filtr is-aktivni' : 'tlacitko tlacitko-filtr'">{$s}</a> <div class="filtry-skupiny" n:if="$skupiny" role="group" aria-label="Filtr skupin">
<a n:foreach="$skupiny as $s" n:href="list, skupina: $s, razeni: $razeni" n:class="$skupina === $s ? 'tlacitko tlacitko-filtr is-aktivni' : 'tlacitko tlacitko-filtr'">{$s}</a>
</div>
<label class="razeni">
<span class="razeni-popisek">Řazení</span>
<select class="razeni-vyber" aria-label="Řazení obvodů" onchange="location.href = this.value">
<option n:foreach="$razeniMoznosti as $klic => $popisek" n:attr="selected: $razeni === $klic" value="{link list, skupina: $skupina, razeni: $klic}">{$popisek}</option>
</select>
</label>
</div> </div>
<table class="tabulka"> <table class="tabulka">

View File

@ -661,16 +661,52 @@ body:has(#map[data-max]) {
} }
.filtry, .filtry,
.akce { .akce,
.filtry-skupiny {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 0.5rem; gap: 0.5rem;
} }
.filtry { .filtry {
align-items: center;
justify-content: space-between;
margin-bottom: 0.85rem; margin-bottom: 0.85rem;
} }
.razeni {
display: flex;
align-items: center;
gap: 0.55rem;
margin-left: auto;
min-width: min(100%, 18.5rem);
}
.razeni-popisek {
color: #1d4f91;
font-weight: 800;
white-space: nowrap;
}
.razeni-vyber {
width: 100%;
min-height: 2.75rem;
padding: 0.4rem 2.3rem 0.4rem 0.95rem;
border-radius: 999px;
border: 2px solid #1d4f91;
background-color: #fff;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%231d4f91' d='M1.2 1.4 6 6.2 10.8 1.4'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 0.9rem center;
color: #1d4f91;
font-weight: 800;
font-size: 0.98rem;
line-height: 1.2;
appearance: none;
cursor: pointer;
box-shadow: 0 4px 12px rgba(29, 79, 145, 0.12);
}
.tlacitko.tlacitko-filtr { .tlacitko.tlacitko-filtr {
background: #f8efd0; background: #f8efd0;
color: #6f5410; color: #6f5410;
@ -966,8 +1002,14 @@ body:has(#map[data-max]) {
.lista > .tlacitko, .lista > .tlacitko,
.akce, .akce,
.formular-akce { .formular-akce,
.razeni {
width: 100%; width: 100%;
margin-left: 0;
}
.razeni-vyber {
font-size: 1rem;
} }
.akce, .akce,