New design

This commit is contained in:
2025-12-20 17:44:35 +01:00
parent c693f7c7ed
commit bc25bb1626
12 changed files with 826 additions and 299 deletions

46
app/Enums/Parties.php Normal file
View File

@@ -0,0 +1,46 @@
<?php
namespace App\Enums;
enum Parties: string
{
case SOCIAL_DEMOCRATS = 'S';
case CENTER_PARTY = 'C';
case LIBERALS = 'L';
case GREEN_PARTY = 'MP';
case LEFT_PARTY = 'V';
case MODERATES = 'M';
case CHRIST_DEMOCRATS = 'KD';
case SWEDEN_DEMOCRATS = 'SD';
case OTHER = '-';
public function label(): string
{
return match ($this) {
self::SOCIAL_DEMOCRATS => 'Socialdemokraterna',
self::CENTER_PARTY => 'Centerpartiet',
self::LIBERALS => 'Liberalerna',
self::GREEN_PARTY => 'Miljöpartiet',
self::LEFT_PARTY => 'Vänsterpartiet',
self::MODERATES => 'Moderaterna',
self::CHRIST_DEMOCRATS => 'Kristdemokraterna',
self::SWEDEN_DEMOCRATS => 'Sverigedemokraterna',
self::OTHER => 'Partilös',
};
}
public function logo(): string
{
return match ($this) {
self::SOCIAL_DEMOCRATS => 'https://bilder.riksdagen.se/publishedmedia/cj3cmk5s63xb1ihzlalj/Symbol_Socialdemokraterna__134px.png',
self::CENTER_PARTY => 'https://bilder.riksdagen.se/publishedmedia/t1cxmh6vk2olrgltat9j/Symbol_Centern_125.png',
self::LIBERALS => 'https://bilder.riksdagen.se/publishedmedia/ve2gtm25br1jr8t8c3mo/L_partilogga.png',
self::GREEN_PARTY => 'https://bilder.riksdagen.se/publishedmedia/zzxff0abnuukdggtqboe/MP_partilogga.png',
self::LEFT_PARTY => 'https://bilder.riksdagen.se/publishedmedia/9ktrv8a5x75lo7zm90pn/Symbol_Va-nsterpartiet_121px.png',
self::MODERATES => 'https://bilder.riksdagen.se/publishedmedia/hxssexpfw01wb5uh3nfp/Symbol_Moderaterna_125px.png',
self::CHRIST_DEMOCRATS => 'https://bilder.riksdagen.se/publishedmedia/sjyk5gmvg3rkxmy2x84o/KD_partilogga.png',
self::SWEDEN_DEMOCRATS => 'https://bilder.riksdagen.se/publishedmedia/aog7hfhgv94tykktrkpy/Sveriedemokraterna_132px.png',
self::OTHER => '-',
};
}
}

View File

@@ -1,29 +0,0 @@
<?php
namespace App\Enums;
enum PartyEnum: string
{
case SOCIAL_DEMOCRATS = 'S';
case CENTER_PARTY = 'C';
case LIBERALS = 'L';
case GREEN_PARTY = 'MP';
case LEFT_PARTY = 'V';
case MODERATES = 'M';
case CHRIST_DEMOCRATS = 'KD';
case SWEDEN_DEMOCRATS = 'SD';
public function label(): string
{
return match ($this) {
self::SOCIAL_DEMOCRATS => 'Socialdemokraterna',
self::CENTER_PARTY => 'Centerpartiet',
self::LIBERALS => 'Liberalerna',
self::GREEN_PARTY => 'Miljöpartiet',
self::LEFT_PARTY => 'Vänsterpartiet',
self::MODERATES => 'Moderaterna',
self::CHRIST_DEMOCRATS => 'Kristdemokraterna',
self::SWEDEN_DEMOCRATS => 'Sverigedemokraterna',
};
}
}

13
app/Livewire/HomePage.php Normal file
View File

@@ -0,0 +1,13 @@
<?php
namespace App\Livewire;
use Livewire\Component;
class HomePage extends Component
{
public function render()
{
return view('livewire.home-page');
}
}

View File

@@ -4,7 +4,7 @@ namespace App\Livewire\Person;
use Livewire\Component; use Livewire\Component;
use App\Services\RiksdagenService; use App\Services\RiksdagenService;
use App\Enums\PartyEnum; use App\Enums\Parties;
class Search extends Component class Search extends Component
{ {
@@ -16,7 +16,7 @@ class Search extends Component
public function mount() public function mount()
{ {
$this->parties = PartyEnum::cases(); $this->parties = collect(Parties::cases())->sortBy(fn($party) => $party->label())->toArray();
} }
public function search() public function search()

View File

@@ -6,7 +6,9 @@ use Livewire\Component;
use App\Services\RiksdagenService; use App\Services\RiksdagenService;
use Livewire\Attributes\Computed; use Livewire\Attributes\Computed;
use Asantibanez\LivewireCharts\Models\PieChartModel; use Asantibanez\LivewireCharts\Models\PieChartModel;
use Livewire\Attributes\Lazy;
#[Lazy()]
class Show extends Component class Show extends Component
{ {
public $personId; public $personId;
@@ -132,8 +134,9 @@ class Show extends Component
$statistics = $this->votingStatistics; $statistics = $this->votingStatistics;
$pieChart = (new PieChartModel()) $pieChart = (new PieChartModel())
->setTitle('Röststatistik för ' . $this->selectedYear) ->setTitle('Voteringsstatistik för ' . $this->selectedYear)
->setAnimated(true); ->setAnimated(true)
->withDataLabels();
$colors = [ $colors = [
'Ja' => '#10b981', // Green 'Ja' => '#10b981', // Green
@@ -150,6 +153,11 @@ class Show extends Component
return $pieChart; return $pieChart;
} }
public function placeholder()
{
return view('livewire.person.show-skeleton');
}
public function render() public function render()
{ {
return view('livewire.person.show'); return view('livewire.person.show');

View File

@@ -1,5 +1,14 @@
<x-layouts.app.sidebar :title="$title ?? null"> <x-layouts.app.sidebar :title="$title ?? null">
<flux:main> <flux:main>
{{ $slot }} {{ $slot }}
<footer>
<!-- Footer Info -->
<div class="text-center text-gray-500">
<p class="text-sm">
Källa <a href="https://riksdagen.se" target="_blank"
class="text-blue-600 hover:text-blue-700 underline">riksdagen.se</a>
</p>
</div>
</footer>
</flux:main> </flux:main>
</x-layouts.app.sidebar> </x-layouts.app.sidebar>

View File

@@ -3,126 +3,10 @@
<head> <head>
@include('partials.head') @include('partials.head')
</head> </head>
<body class="min-h-screen bg-white dark:bg-zinc-800"> <body class="min-h-screen bg-white from-blue-50 to-indigo-100 bg-gradient-to-br">
<flux:sidebar sticky stashable class="border-e border-zinc-200 bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900">
<flux:sidebar.toggle class="lg:hidden" icon="x-mark" />
<a href="{{ route('dashboard') }}" class="me-5 flex items-center space-x-2 rtl:space-x-reverse" wire:navigate>
<x-app-logo />
</a>
<flux:navlist variant="outline">
<flux:navlist.group :heading="__('Platform')" class="grid">
<flux:navlist.item icon="home" :href="route('dashboard')" :current="request()->routeIs('dashboard')" wire:navigate>{{ __('Dashboard') }}</flux:navlist.item>
</flux:navlist.group>
</flux:navlist>
<flux:spacer />
<flux:navlist variant="outline">
<flux:navlist.item icon="folder-git-2" href="https://github.com/laravel/livewire-starter-kit" target="_blank">
{{ __('Repository') }}
</flux:navlist.item>
<flux:navlist.item icon="book-open-text" href="https://laravel.com/docs/starter-kits#livewire" target="_blank">
{{ __('Documentation') }}
</flux:navlist.item>
</flux:navlist>
<!-- Desktop User Menu -->
<flux:dropdown class="hidden lg:block" position="bottom" align="start">
<flux:profile
:name="auth()->user()?->name"
:initials="auth()->user()?->initials()"
icon:trailing="chevrons-up-down"
/>
<flux:menu class="w-[220px]">
<flux:menu.radio.group>
<div class="p-0 text-sm font-normal">
<div class="flex items-center gap-2 px-1 py-1.5 text-start text-sm">
<span class="relative flex h-8 w-8 shrink-0 overflow-hidden rounded-lg">
<span
class="flex h-full w-full items-center justify-center rounded-lg bg-neutral-200 text-black dark:bg-neutral-700 dark:text-white"
>
{{ auth()->user()?->initials() }}
</span>
</span>
<div class="grid flex-1 text-start text-sm leading-tight">
<span class="truncate font-semibold">{{ auth()->user()?->name }}</span>
<span class="truncate text-xs">{{ auth()->user()?->email }}</span>
</div>
</div>
</div>
</flux:menu.radio.group>
<flux:menu.separator />
<flux:menu.radio.group>
<flux:menu.item :href="route('profile.edit')" icon="cog" wire:navigate>{{ __('Settings') }}</flux:menu.item>
</flux:menu.radio.group>
<flux:menu.separator />
<form method="POST" action="{{ route('logout') }}" class="w-full">
@csrf
<flux:menu.item as="button" type="submit" icon="arrow-right-start-on-rectangle" class="w-full">
{{ __('Log Out') }}
</flux:menu.item>
</form>
</flux:menu>
</flux:dropdown>
</flux:sidebar>
<!-- Mobile User Menu --> <!-- Mobile User Menu -->
<flux:header class="lg:hidden"> <flux:header class="lg:hidden">
<flux:sidebar.toggle class="lg:hidden" icon="bars-2" inset="left" />
<flux:spacer />
<flux:dropdown position="top" align="end">
<flux:profile
:initials="auth()->user()?->initials()"
icon-trailing="chevron-down"
/>
<flux:menu>
<flux:menu.radio.group>
<div class="p-0 text-sm font-normal">
<div class="flex items-center gap-2 px-1 py-1.5 text-start text-sm">
<span class="relative flex h-8 w-8 shrink-0 overflow-hidden rounded-lg">
<span
class="flex h-full w-full items-center justify-center rounded-lg bg-neutral-200 text-black dark:bg-neutral-700 dark:text-white"
>
{{ auth()->user()?->initials() }}
</span>
</span>
<div class="grid flex-1 text-start text-sm leading-tight">
<span class="truncate font-semibold">{{ auth()->user()?->name }}</span>
<span class="truncate text-xs">{{ auth()->user()?->email }}</span>
</div>
</div>
</div>
</flux:menu.radio.group>
<flux:menu.separator />
<flux:menu.radio.group>
<flux:menu.item :href="route('profile.edit')" icon="cog" wire:navigate>{{ __('Settings') }}</flux:menu.item>
</flux:menu.radio.group>
<flux:menu.separator />
<form method="POST" action="{{ route('logout') }}" class="w-full">
@csrf
<flux:menu.item as="button" type="submit" icon="arrow-right-start-on-rectangle" class="w-full">
{{ __('Log Out') }}
</flux:menu.item>
</form>
</flux:menu>
</flux:dropdown>
</flux:header> </flux:header>
{{ $slot }} {{ $slot }}

View File

@@ -0,0 +1,131 @@
<div class="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
<div class="container mx-auto py-12 px-4">
<!-- Header Section -->
<div class="text-center mb-12">
<h1 class="text-4xl md:text-5xl font-bold text-gray-900 mb-4">
Riksdagen App
</h1>
<p class="text-lg text-gray-600 max-w-2xl mx-auto">
Utforska information om riksdagsledamöter, deras röster och uppdrag i Sveriges riksdag
</p>
</div>
<!-- Navigation Cards -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 max-w-6xl mx-auto">
<!-- Person Search Card -->
<a wire:navigate href="{{ route('person.search') }}" class="group">
<div class="bg-white rounded-lg shadow-md hover:shadow-xl transition-all duration-300 transform hover:-translate-y-1 border border-gray-200 overflow-hidden">
<div class="p-6">
<div class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center mb-4 group-hover:bg-blue-200 transition-colors">
<svg class="w-6 h-6 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
</svg>
</div>
<h3 class="text-xl font-semibold text-gray-900 mb-2">Ledamöter</h3>
<p class="text-gray-600 mb-4">
Sök och utforska information om riksdagsledamöter, deras rösthistorik och uppdrag
</p>
<div class="flex items-center text-blue-600 group-hover:text-blue-700">
<span class="text-sm font-medium">Sök ledamöter</span>
<svg class="w-4 h-4 ml-2 transform group-hover:translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
</svg>
</div>
</div>
</div>
</a>
<!-- Placeholder Card 1 -->
<div class="bg-white rounded-lg shadow-md border border-gray-200 overflow-hidden opacity-60">
<div class="p-6">
<div class="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4">
<svg class="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path>
</svg>
</div>
<h3 class="text-xl font-semibold text-gray-500 mb-2">Propositioner</h3>
<p class="text-gray-400 mb-4">
Sök och läs propositioner och andra dokument från riksdagen
</p>
<div class="flex items-center text-gray-400">
<span class="text-sm font-medium">Kommer snart</span>
</div>
</div>
</div>
<!-- Placeholder Card 2 -->
<div class="bg-white rounded-lg shadow-md border border-gray-200 overflow-hidden opacity-60">
<div class="p-6">
<div class="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4">
<svg class="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
</svg>
</div>
<h3 class="text-xl font-semibold text-gray-500 mb-2">Statistik</h3>
<p class="text-gray-400 mb-4">
Se röststatistik och analyser för partier och ledamöter
</p>
<div class="flex items-center text-gray-400">
<span class="text-sm font-medium">Kommer snart</span>
</div>
</div>
</div>
<!-- Placeholder Card 3 -->
<div class="bg-white rounded-lg shadow-md border border-gray-200 overflow-hidden opacity-60">
<div class="p-6">
<div class="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4">
<svg class="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
</svg>
</div>
<h3 class="text-xl font-semibold text-gray-500 mb-2">Kalender</h3>
<p class="text-gray-400 mb-4">
Se kommande voteringar och riksdagsmöten
</p>
<div class="flex items-center text-gray-400">
<span class="text-sm font-medium">Kommer snart</span>
</div>
</div>
</div>
<!-- Placeholder Card 4 -->
<div class="bg-white rounded-lg shadow-md border border-gray-200 overflow-hidden opacity-60">
<div class="p-6">
<div class="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4">
<svg class="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"></path>
</svg>
</div>
<h3 class="text-xl font-semibold text-gray-500 mb-2">Partier</h3>
<p class="text-gray-400 mb-4">
Utforska partier och deras ståndpunkter i olika frågor
</p>
<div class="flex items-center text-gray-400">
<span class="text-sm font-medium">Kommer snart</span>
</div>
</div>
</div>
<!-- Placeholder Card 5 -->
<div class="bg-white rounded-lg shadow-md border border-gray-200 overflow-hidden opacity-60">
<div class="p-6">
<div class="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4">
<svg class="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
</svg>
</div>
<h3 class="text-xl font-semibold text-gray-500 mb-2">Sök Allmänt</h3>
<p class="text-gray-400 mb-4">
Sök i alla riksdagens dokument och voteringar
</p>
<div class="flex items-center text-gray-400">
<span class="text-sm font-medium">Kommer snart</span>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@@ -1,60 +1,130 @@
<div class="container mx-auto py-8"> <div class="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
<h1 class="text-2xl font-bold mb-6">Sök person</h1> <div class="container mx-auto py-12 px-4">
<form wire:submit.prevent="search" class="mb-8 flex flex-col md:flex-row gap-4 items-end"> <!-- Header Section -->
<div class="text-center mb-12">
<div class="flex items-center justify-center mb-6">
<a wire:navigate href="{{ route('home') }}" class="text-blue-600 hover:text-blue-700 mr-4">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M10 19l-7-7m0 0l7-7m-7 7h18"></path>
</svg>
</a>
<div class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center">
<svg class="w-6 h-6 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
</svg>
</div>
</div>
<h1 class="text-4xl md:text-5xl font-bold text-gray-900 mb-4">Sök Ledamöter</h1>
<p class="text-lg text-gray-600 max-w-2xl mx-auto mb-8">
Sök efter riksdagsledamöter genom namn eller parti och utforska deras rösthistorik och uppdrag
</p>
</div>
<!-- Search Form -->
<div class="bg-white rounded-lg shadow-md border border-gray-200 p-6 mb-8 max-w-4xl mx-auto">
<form wire:submit.prevent="search" class="flex flex-col md:flex-row gap-4 items-end">
<div class="flex-1"> <div class="flex-1">
<label for="firstName" class="block text-sm font-medium">Förnamn</label> <input id="firstName" type="text" wire:model.defer="firstName"
<input id="firstName" type="text" wire:model.defer="firstName" class="mt-1 block w-full border rounded px-3 py-2" placeholder="Förnamn..."> class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors text-black"
placeholder="Förnamn...">
</div> </div>
<div class="flex-1"> <div class="flex-1">
<label for="lastName" class="block text-sm font-medium">Efternamn</label> <input id="lastName" type="text" wire:model.defer="lastName"
<input id="lastName" type="text" wire:model.defer="lastName" class="mt-1 block w-full border rounded px-3 py-2" placeholder="Efternamn..."> class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors text-black"
placeholder="Efternamn...">
</div> </div>
<div> <div class="md:w-48">
<label for="party" class="block text-sm font-medium">Parti</label> <select id="party" wire:model.defer="party"
<select id="party" wire:model.defer="party" class="mt-1 block w-full border rounded px-3 py-2"> class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors text-black">
<option value="" class="text-black">Alla partier</option> <option value="" class="text-gray-700">Alla partier</option>
@foreach($parties as $partyOption) @foreach ($parties as $partyOption)
<option class="text-black" value="{{ $partyOption->value }}">{{ $partyOption->label() }}</option> <option class="text-gray-700" value="{{ $partyOption->value }}">{{ $partyOption->label() }}
</option>
@endforeach @endforeach
</select> </select>
</div> </div>
<button type="submit" class="bg-blue-600 text-white px-6 py-2 rounded">Sök</button> <button type="submit"
</form> class="bg-blue-600 hover:bg-blue-700 text-white px-8 py-2 rounded-lg font-medium transition-colors duration-200 flex items-center cursor-pointer">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<div class="text-center" wire:loading> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
<div role="status"> d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
<svg aria-hidden="true" class="w-8 h-8 text-neutral-tertiary animate-spin fill-brand" viewBox="0 0 100 101" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z" fill="currentColor"/>
<path d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z" fill="currentFill"/>
</svg> </svg>
<span class="sr-only">Loading...</span> Sök
</div> </button>
</form>
</div> </div>
@if($results && isset($results->personlista->person)) <!-- Loading State -->
<div class="shadow rounded p-4"> <div class="hidden" wire:loading.block wire:target="search">
<h2 class="text-lg font-semibold mb-4">Resultat</h2> <div class="flex justify-center items-center py-16">
<ul> <div class="w-12 h-12 border-4 border-t-blue-600 border-blue-200 rounded-full animate-spin"></div>
<span class="ml-4 text-gray-600 font-medium">Söker ledamöter...</span>
</div>
</div>
<!-- Results Section -->
<div wire:loading.remove>
@if ($results && isset($results->personlista->person))
<div class="bg-white rounded-lg shadow-md border border-gray-200 p-6 max-w-4xl mx-auto">
<div class="flex items-center mb-6">
<svg class="w-5 h-5 text-green-600 mr-2" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
<h2 class="text-xl font-semibold text-gray-900">Sökresultat</h2>
</div>
<div class="space-y-4">
@php @php
$persons = $results->personlista->person; $persons = $results->personlista->person;
if (!is_array($persons) || (isset($persons->intressent_id) && is_string($persons->intressent_id))) { if (
!is_array($persons) ||
(isset($persons->intressent_id) && is_string($persons->intressent_id))
) {
$persons = [$persons]; $persons = [$persons];
} }
@endphp @endphp
@foreach($persons as $person) @foreach ($persons as $person)
<li class="mb-4 flex items-center border-b pb-4"> <div
<img src="{{ $person->bild_url_192 ?? '' }}" alt="{{ $person->tilltalsnamn }}" class="w-16 h-16 rounded mr-4"> class="bg-gray-50 rounded-lg p-4 hover:bg-gray-100 transition-colors border border-gray-200">
<div class="flex items-center">
<img src="{{ $person->bild_url_80 ?? '' }}" alt="{{ $person->tilltalsnamn }}"
class="w-16 h-16 rounded-lg object-cover mr-4 border border-gray-300">
<div class="flex-1"> <div class="flex-1">
<a wire:navigate href="{{ route('person.show', $person->intressent_id) }}" class="text-blue-700 font-bold text-lg hover:underline"> <a wire:navigate href="{{ route('person.show', $person->intressent_id) }}"
{{ $person->tilltalsnamn }} {{ $person->efternamn }} class="text-xl font-bold text-blue-600 hover:text-blue-700 transition-colors">
{{ $person->tilltalsnamn }} {{ $person->efternamn }} ({{ $person->parti }})
</a> </a>
<div class="text-sm text-gray-600">{{ $person->parti }} | {{ $person->valkrets }}</div> <div class="text-gray-600 mt-1 flex items-center gap-2">
<img src="{{ App\Enums\Parties::from($person->parti)->logo() }}"
width="32">
{{ $person->valkrets }}
</div>
<div class="text-sm text-gray-500 mt-1">{{ $person->status }}</div>
</div>
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 5l7 7-7 7"></path>
</svg>
</div>
</div> </div>
</li>
@endforeach @endforeach
</ul>
</div> </div>
@elseif($results && (!isset($results->personlista->person) || empty($results->personlista->person))) </div>
<div class="text-red-600">Inga personer hittades.</div> </div>
@elseif ($results && (!isset($results->personlista->person) || empty($results->personlista->person)))
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-6 max-w-4xl mx-auto">
<div class="flex items-center">
<svg class="w-5 h-5 text-yellow-600 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
<span class="text-yellow-800 font-medium">Inga ledamöter hittades med de angivna sökkriterier.</span>
</div>
</div>
@endif @endif
</div>
</div>
</div> </div>

View File

@@ -0,0 +1,254 @@
{{-- Skeleton loading placeholder for person show page --}}
<div class="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 animate-pulse">
<div class="container mx-auto py-12 px-4">
<!-- Breadcrumb Navigation Skeleton -->
<nav class="mb-8">
<div class="bg-white rounded-lg shadow-sm border border-gray-200 px-4 py-3">
<div class="flex items-center space-x-2">
<div class="h-4 bg-gray-200 rounded w-12"></div>
<div class="w-4 h-4 bg-gray-200 rounded"></div>
<div class="h-4 bg-gray-200 rounded w-20"></div>
<div class="w-4 h-4 bg-gray-200 rounded"></div>
<div class="h-4 bg-gray-200 rounded w-24"></div>
</div>
</div>
</nav>
<!-- Main Profile Card Skeleton -->
<div class="bg-white rounded-lg shadow-md border border-gray-200 p-8 mb-8">
<div class="flex flex-col md:flex-row gap-8">
{{-- Profile image skeleton --}}
<div class="md:w-48">
<div class="w-full h-64 md:w-48 bg-gray-300 rounded-lg border border-gray-200"></div>
</div>
{{-- Main content skeleton --}}
<div class="flex-1">
<div class="mb-6">
{{-- Name skeleton --}}
<div class="h-10 bg-gray-300 rounded mb-2 w-3/4"></div>
<div class="flex flex-wrap items-center gap-4 mb-4">
<div class="h-6 bg-gray-200 rounded-full w-16"></div>
<div class="h-5 bg-gray-200 rounded w-32"></div>
</div>
</div>
{{-- Info grid skeleton --}}
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
<div class="bg-gray-50 rounded-lg p-4">
<div class="h-3 bg-gray-300 rounded mb-1 w-12"></div>
<div class="h-5 bg-gray-200 rounded w-16"></div>
</div>
<div class="bg-gray-50 rounded-lg p-4">
<div class="h-3 bg-gray-300 rounded mb-1 w-8"></div>
<div class="h-5 bg-gray-200 rounded w-12"></div>
</div>
<div class="bg-gray-50 rounded-lg p-4">
<div class="h-3 bg-gray-300 rounded mb-1 w-12"></div>
<div class="h-5 bg-gray-200 rounded w-24"></div>
</div>
<div class="bg-gray-50 rounded-lg p-4">
<div class="h-3 bg-gray-300 rounded mb-1 w-12"></div>
<div class="h-5 bg-gray-200 rounded w-32"></div>
</div>
</div>
{{-- Action button skeleton --}}
<div class="h-10 bg-gray-200 rounded-lg w-40"></div>
</div>
</div>
</div>
<!-- Assignments Card Skeleton -->
<div class="bg-white rounded-lg shadow-md border border-gray-200 p-6 mb-8">
<div class="flex items-center mb-6">
<div class="w-10 h-10 bg-gray-200 rounded-lg mr-3"></div>
<div class="h-8 bg-gray-300 rounded w-24"></div>
</div>
{{-- Uppdrag tabs skeleton --}}
<div class="border-b border-gray-200 mb-6">
<nav class="-mb-px flex space-x-8">
<div class="py-3 px-1 border-b-2 border-blue-500">
<div class="flex items-center">
<div class="w-4 h-4 bg-gray-200 rounded mr-2"></div>
<div class="h-5 bg-gray-200 rounded w-20"></div>
</div>
</div>
<div class="py-3 px-1">
<div class="flex items-center">
<div class="w-4 h-4 bg-gray-200 rounded mr-2"></div>
<div class="h-5 bg-gray-200 rounded w-16"></div>
</div>
</div>
</nav>
</div>
{{-- Uppdrag cards skeleton --}}
<div class="space-y-4">
<div class="bg-green-50 border border-green-200 rounded-lg p-4">
<div class="flex justify-between items-start">
<div class="flex-1">
<div class="h-5 bg-gray-300 rounded mb-2 w-2/3"></div>
<div class="h-4 bg-gray-200 rounded mb-1 w-1/2"></div>
</div>
<div class="text-right">
<div class="h-4 bg-gray-200 rounded mb-1 w-16"></div>
<div class="h-4 bg-gray-200 rounded w-12"></div>
</div>
</div>
</div>
<div class="bg-green-50 border border-green-200 rounded-lg p-4">
<div class="flex justify-between items-start">
<div class="flex-1">
<div class="h-5 bg-gray-300 rounded mb-2 w-3/4"></div>
<div class="h-4 bg-gray-200 rounded mb-1 w-1/3"></div>
</div>
<div class="text-right">
<div class="h-4 bg-gray-200 rounded mb-1 w-16"></div>
<div class="h-4 bg-gray-200 rounded w-12"></div>
</div>
</div>
</div>
</div>
</div>
<!-- Biography Card Skeleton -->
<div class="bg-white rounded-lg shadow-md border border-gray-200 p-6 mb-8">
<div class="flex items-center mb-6">
<div class="w-10 h-10 bg-gray-200 rounded-lg mr-3"></div>
<div class="h-8 bg-gray-300 rounded w-24"></div>
</div>
<div class="space-y-4">
<div class="bg-gray-50 rounded-lg p-4">
<div class="h-5 bg-gray-300 rounded mb-2 w-24"></div>
<div class="h-4 bg-gray-200 rounded w-3/4"></div>
</div>
<div class="bg-gray-50 rounded-lg p-4">
<div class="h-5 bg-gray-300 rounded mb-2 w-20"></div>
<div class="h-4 bg-gray-200 rounded w-2/3"></div>
</div>
<div class="bg-gray-50 rounded-lg p-4">
<div class="h-5 bg-gray-300 rounded mb-2 w-28"></div>
<div class="h-4 bg-gray-200 rounded w-1/2"></div>
</div>
</div>
</div>
<!-- Voting Section Card Skeleton -->
<div class="bg-white rounded-lg shadow-md border border-gray-200 p-6 mb-8">
<div class="flex items-center mb-6">
<div class="w-10 h-10 bg-gray-200 rounded-lg mr-3"></div>
<div class="h-8 bg-gray-300 rounded w-24"></div>
</div>
{{-- Year tabs skeleton --}}
<div class="border-b border-gray-200 mb-6">
<nav class="-mb-px flex space-x-8">
<div class="py-3 px-1 border-b-2 border-blue-500">
<div class="h-5 bg-gray-200 rounded w-12"></div>
</div>
<div class="py-3 px-1">
<div class="h-5 bg-gray-200 rounded w-12"></div>
</div>
<div class="py-3 px-1">
<div class="h-5 bg-gray-200 rounded w-12"></div>
</div>
</nav>
</div>
{{-- Voting statistics chart skeleton --}}
<div class="bg-white rounded-lg border border-gray-200 p-6 mb-8">
<div class="h-6 bg-gray-300 rounded mb-4 w-1/3"></div>
<div class="flex flex-col lg:flex-row gap-6">
<div class="lg:w-1/2">
{{-- Chart placeholder --}}
<div class="h-64 bg-gray-100 rounded-lg flex items-center justify-center">
<div class="w-32 h-32 bg-gray-300 rounded-full"></div>
</div>
</div>
<div class="lg:w-1/2">
<div class="space-y-2">
<div class="flex justify-between items-center p-3 bg-gray-50 rounded">
<div class="h-5 bg-gray-300 rounded w-16"></div>
<div class="h-5 bg-gray-300 rounded w-8"></div>
</div>
<div class="flex justify-between items-center p-3 bg-gray-50 rounded">
<div class="h-5 bg-gray-300 rounded w-12"></div>
<div class="h-5 bg-gray-300 rounded w-8"></div>
</div>
<div class="flex justify-between items-center p-3 bg-gray-50 rounded">
<div class="h-5 bg-gray-300 rounded w-20"></div>
<div class="h-5 bg-gray-300 rounded w-8"></div>
</div>
<div class="flex justify-between items-center p-3 bg-blue-50 rounded border-t-2 border-blue-500">
<div class="h-5 bg-gray-300 rounded w-32"></div>
<div class="h-5 bg-gray-300 rounded w-10"></div>
</div>
</div>
</div>
</div>
</div>
{{-- Voting table skeleton --}}
<div class="overflow-x-auto">
<div class="min-w-full bg-white border border-gray-200 rounded-lg">
{{-- Table header skeleton --}}
<div class="bg-gray-50 border-b border-gray-200 rounded-t-lg">
<div class="flex">
<div class="px-4 py-3 flex-1">
<div class="h-4 bg-gray-300 rounded w-16"></div>
</div>
<div class="px-4 py-3 flex-1">
<div class="h-4 bg-gray-300 rounded w-20"></div>
</div>
<div class="px-4 py-3 flex-1">
<div class="h-4 bg-gray-300 rounded w-12"></div>
</div>
<div class="px-4 py-3 flex-1">
<div class="h-4 bg-gray-300 rounded w-10"></div>
</div>
<div class="px-4 py-3 flex-1">
<div class="h-4 bg-gray-300 rounded w-16"></div>
</div>
<div class="px-4 py-3 flex-1">
<div class="h-4 bg-gray-300 rounded w-18"></div>
</div>
</div>
</div>
{{-- Table rows skeleton --}}
@for($i = 0; $i < 5; $i++)
<div class="border-b border-gray-100">
<div class="flex">
<div class="px-4 py-3 flex-1">
<div class="h-4 bg-gray-200 rounded w-20"></div>
</div>
<div class="px-4 py-3 flex-1">
<div class="h-4 bg-gray-200 rounded w-16"></div>
</div>
<div class="px-4 py-3 flex-1">
<div class="h-4 bg-gray-200 rounded w-8"></div>
</div>
<div class="px-4 py-3 flex-1">
<div class="h-6 bg-gray-200 rounded-full w-12"></div>
</div>
<div class="px-4 py-3 flex-1">
<div class="h-4 bg-gray-200 rounded w-14"></div>
</div>
<div class="px-4 py-3 flex-1">
<div class="h-4 bg-gray-200 rounded w-16"></div>
</div>
</div>
</div>
@endfor
</div>
</div>
</div>
<!-- Footer Skeleton -->
<div class="text-center mt-8">
<div class="bg-white rounded-lg shadow-sm border border-gray-200 px-6 py-4">
<div class="h-4 bg-gray-200 rounded w-48 mx-auto"></div>
</div>
</div>
</div>

View File

@@ -1,57 +1,159 @@
<div class="container mx-auto py-8"> <div class="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
@if($person) <div class="container mx-auto py-12 px-4">
<!-- Breadcrumb Navigation -->
<nav class="mb-8" aria-label="Breadcrumb">
<div class="bg-white rounded-lg shadow-sm border border-gray-200 px-4 py-3">
<ol class="flex items-center space-x-2 text-sm text-gray-600">
<li>
<a wire:navigate href="{{ route('home') }}" class="text-blue-600 hover:text-blue-700 flex items-center">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6">
</path>
</svg>
Hem
</a>
</li>
<li>
<svg class="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd"></path>
</svg>
</li>
<li>
<a wire:navigate href="{{ route('person.search') }}" class="text-blue-600 hover:text-blue-700">Sök
Ledamöter</a>
</li>
<li>
<svg class="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd"></path>
</svg>
</li>
<li class="font-medium text-gray-900">
{{ $person->tilltalsnamn ?? 'Laddar...' }} {{ $person->efternamn ?? '' }}
</li>
</ol>
</div>
</nav>
@if ($person)
<!-- Main Profile Section -->
<div class="bg-white rounded-lg shadow-md border border-gray-200 p-8 mb-8">
<div class="flex flex-col md:flex-row gap-8"> <div class="flex flex-col md:flex-row gap-8">
<div> <div class="md:w-48">
<img src="{{ $person->bild_url_max ?? '' }}" alt="{{ $person->tilltalsnamn }}" class="w-48 h-64 object-cover rounded shadow"> <img src="{{ $person->bild_url_max ?? '' }}" alt="{{ $person->tilltalsnamn }}"
class="w-full h-64 md:w-48 object-cover rounded-lg shadow-lg border border-gray-200">
</div> </div>
<div class="flex-1"> <div class="flex-1">
<h1 class="text-3xl font-bold mb-2">{{ $person->tilltalsnamn }} {{ $person->efternamn }}</h1> <div class="mb-6">
<div class="mb-2 text-lg text-gray-500">{{ $person->parti }} | {{ $person->valkrets }}</div> <h1 class="text-4xl font-bold text-gray-900 mb-2">{{ $person->tilltalsnamn }}
<div class="mb-2">Född: {{ $person->fodd_ar }} | Kön: {{ ucfirst($person->kon) }}</div> {{ $person->efternamn }} ({{ $person->parti }})</h1>
<div class="mb-2">Status: {{ $person->status }}</div> <div class="flex flex-wrap items-center gap-4 mb-4">
<div class="mb-2">E-post: {{ str_replace('[på]', '@', collect($person->personuppgift->uppgift ?? [])->firstWhere('kod', 'Officiell e-postadress')->uppgift[0] ?? '-') }}</div> <span
<div class="mb-4"> class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-blue-100 text-blue-800 grap-2">
<a href="{{ $this->riksdagen_url }}" class="text-blue-600 underline" target="_blank">Visa riksdagen.se</a> {{ App\Enums\Parties::from($person->parti)->label() }}
<img src="{{ App\Enums\Parties::from($person->parti)->logo() }}" width="32">
</span>
<span class="text-gray-600">{{ $person->valkrets }} valkrets</span>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
<div class="bg-gray-50 rounded-lg p-4">
<div class="text-sm font-medium text-gray-500 mb-1">Född</div>
<div class="text-gray-900">{{ $person->fodd_ar }}</div>
</div>
<div class="bg-gray-50 rounded-lg p-4">
<div class="text-sm font-medium text-gray-500 mb-1">Kön</div>
<div class="text-gray-900">{{ ucfirst($person->kon) }}</div>
</div>
<div class="bg-gray-50 rounded-lg p-4">
<div class="text-sm font-medium text-gray-500 mb-1">Status</div>
<div class="text-gray-900">{{ $person->status }}</div>
</div>
<div class="bg-gray-50 rounded-lg p-4">
<div class="text-sm font-medium text-gray-500 mb-1">E-post</div>
<div class="text-gray-900 text-sm">
{{ str_replace('[på]', '@', collect($person->personuppgift->uppgift ?? [])->firstWhere('kod', 'Officiell e-postadress')->uppgift[0] ?? '-') }}
</div>
</div>
</div>
<a href="{{ $this->riksdagen_url }}" target="_blank"
class="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14">
</path>
</svg>
Visa riksdagen.se
</a>
</div>
</div>
</div>
<!-- Assignments Section -->
<div class="bg-white rounded-lg shadow-md border border-gray-200 p-6 mb-8">
<div class="flex items-center mb-6">
<div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center mr-3">
<svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M21 13.255A23.931 23.931 0 0112 15c-3.183 0-6.22-.62-9-1.745M16 6V4a2 2 0 00-2-2h-4a2 2 0 00-2-2v2m8 0H8m8 0v2a2 2 0 01-2 2H10a2 2 0 01-2-2V6">
</path>
</svg>
</div>
<h2 class="text-2xl font-bold text-gray-900">Uppdrag</h2>
</div> </div>
<h2 class="text-xl font-semibold mt-6 mb-4">Uppdrag</h2>
<!-- Uppdrag tabs --> <!-- Uppdrag tabs -->
<div class="border-b border-gray-200 mb-4"> <div class="border-b border-gray-200 mb-6">
<nav class="-mb-px flex space-x-8"> <nav class="-mb-px flex space-x-8">
<button <button wire:click="selectUppdragTab('current')"
wire:click="selectUppdragTab('current')" class="py-3 px-1 border-b-2 font-medium text-sm transition-colors {{ $selectedUppdragTab == 'current' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300' }}">
class="py-2 cursor-pointer px-1 border-b-2 font-medium text-sm {{ $selectedUppdragTab == 'current' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300' }}"> <span class="flex items-center">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
Pågående ({{ count($currentUppdrag) }}) Pågående ({{ count($currentUppdrag) }})
</span>
</button> </button>
<button <button wire:click="selectUppdragTab('previous')"
wire:click="selectUppdragTab('previous')" class="py-3 px-1 border-b-2 font-medium text-sm transition-colors {{ $selectedUppdragTab == 'previous' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300' }}">
class="py-2 cursor-pointer px-1 border-b-2 font-medium text-sm {{ $selectedUppdragTab == 'previous' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300' }}"> <span class="flex items-center">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
Tidigare ({{ count($previousUppdrag) }}) Tidigare ({{ count($previousUppdrag) }})
</span>
</button> </button>
</nav> </nav>
</div> </div>
<!-- Current assignments --> <!-- Current assignments -->
@if($selectedUppdragTab == 'current' && !empty($currentUppdrag)) @if ($selectedUppdragTab == 'current' && !empty($currentUppdrag))
<div class="space-y-3"> <div class="space-y-3">
@foreach($currentUppdrag as $uppdrag) @foreach ($currentUppdrag as $uppdrag)
<div class="bg-green-50 border border-green-200 rounded-lg p-4"> <div class="bg-green-50 border border-green-200 rounded-lg p-4">
<div class="flex justify-between items-start"> <div class="flex justify-between items-start">
<div> <div>
<h4 class="font-semibold text-green-800">{{ $uppdrag->roll_kod }}</h4> <h4 class="font-semibold text-green-800">{{ $uppdrag->roll_kod }}</h4>
{{-- @if(!empty($uppdrag->uppgift[0]) && is_array($uppdrag->uppgift)) {{-- @if (!empty($uppdrag->uppgift[0]) && is_array($uppdrag->uppgift))
<p class="text-sm text-green-700 mt-1">{{ implode(', ', $uppdrag->uppgift) }}</p> <p class="text-sm text-green-700 mt-1">{{ implode(', ', $uppdrag->uppgift) }}</p>
@endif --}} @endif --}}
<p class="text-sm text-green-600 mt-2"> <p class="text-sm text-green-600 mt-2">
<span class="font-medium">Typ:</span> {{ ucfirst($uppdrag->typ) }} <span class="font-medium">Typ:</span> {{ ucfirst($uppdrag->typ) }}
@if(isset($uppdrag->status) && $uppdrag->status) @if (isset($uppdrag->status) && $uppdrag->status)
| <span class="font-medium">Status:</span> {{ $uppdrag->status }} | <span class="font-medium">Status:</span> {{ $uppdrag->status }}
@endif @endif
</p> </p>
</div> </div>
<div class="text-right text-sm text-green-600"> <div class="text-right text-sm text-green-600">
<div>Från: {{ Carbon\Carbon::parse($uppdrag->from)->format('Y-m-d') }}</div> <div>Från: {{ Carbon\Carbon::parse($uppdrag->from)->format('Y-m-d') }}</div>
@if(!empty($uppdrag->tom)) @if (!empty($uppdrag->tom))
<div>Till: {{ Carbon\Carbon::parse($uppdrag->tom)->format('Y-m-d') }}</div> <div>Till: {{ Carbon\Carbon::parse($uppdrag->tom)->format('Y-m-d') }}</div>
@else @else
<div class="font-semibold text-green-700">Pågående</div> <div class="font-semibold text-green-700">Pågående</div>
@@ -66,25 +168,26 @@
@endif @endif
<!-- Previous assignments --> <!-- Previous assignments -->
@if($selectedUppdragTab == 'previous' && !empty($previousUppdrag)) @if ($selectedUppdragTab == 'previous' && !empty($previousUppdrag))
<div class="space-y-3"> <div class="space-y-3">
@foreach($previousUppdrag as $uppdrag) @foreach ($previousUppdrag as $uppdrag)
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4"> <div class="bg-gray-50 border border-gray-200 rounded-lg p-4">
<div class="flex justify-between items-start"> <div class="flex justify-between items-start">
<div> <div>
<h4 class="font-semibold text-gray-800">{{ $uppdrag->roll_kod }}</h4> <h4 class="font-semibold text-gray-800">{{ $uppdrag->roll_kod }}</h4>
{{-- @if(!empty($uppdrag->uppgift[0]) && is_array($uppdrag->uppgift)) {{-- @if (!empty($uppdrag->uppgift[0]) && is_array($uppdrag->uppgift))
<p class="text-sm text-gray-700 mt-1">{{ implode(', ', $uppdrag->uppgift) }}</p> <p class="text-sm text-gray-700 mt-1">{{ implode(', ', $uppdrag->uppgift) }}</p>
@endif --}} @endif --}}
<p class="text-sm text-gray-600 mt-2"> <p class="text-sm text-gray-600 mt-2">
<span class="font-medium">Typ:</span> {{ ucfirst($uppdrag->typ) }} <span class="font-medium">Typ:</span> {{ ucfirst($uppdrag->typ) }}
@if(isset($uppdrag->status) && $uppdrag->status) @if (isset($uppdrag->status) && $uppdrag->status)
| <span class="font-medium">Status:</span> {{ $uppdrag->status }} | <span class="font-medium">Status:</span> {{ $uppdrag->status }}
@endif @endif
</p> </p>
</div> </div>
<div class="text-right text-sm text-gray-600"> <div class="text-right text-sm text-gray-600">
<div>{{ Carbon\Carbon::parse($uppdrag->from)->format('Y-m-d') }} - {{ Carbon\Carbon::parse($uppdrag->tom)->format('Y-m-d') }}</div> <div>{{ Carbon\Carbon::parse($uppdrag->from)->format('Y-m-d') }} -
{{ Carbon\Carbon::parse($uppdrag->tom)->format('Y-m-d') }}</div>
<div class="text-xs text-gray-500 mt-1"> <div class="text-xs text-gray-500 mt-1">
{{ Carbon\Carbon::parse($uppdrag->from)->diffForHumans(Carbon\Carbon::parse($uppdrag->tom), true) }} {{ Carbon\Carbon::parse($uppdrag->from)->diffForHumans(Carbon\Carbon::parse($uppdrag->tom), true) }}
</div> </div>
@@ -96,24 +199,27 @@
@elseif($selectedUppdragTab == 'previous' && empty($previousUppdrag)) @elseif($selectedUppdragTab == 'previous' && empty($previousUppdrag))
<p class="text-gray-500 italic">Inga tidigare uppdrag registrerade.</p> <p class="text-gray-500 italic">Inga tidigare uppdrag registrerade.</p>
@endif @endif
<h2 class="text-xl font-semibold mt-6 mb-2">Biografi</h2> </div>
<ul class="list-disc ml-6"> @if (!empty($votesByYear))
@foreach(collect($person->personuppgift->uppgift ?? [])->where('typ', 'biografi') as $bio) <!-- Voting Section -->
<li> <div class="bg-white rounded-lg shadow-md border border-gray-200 p-6 mb-8">
<strong>{{ $bio->kod }}:</strong> {{ is_array($bio->uppgift) ? implode(', ', $bio->uppgift) : $bio->uppgift }} <div class="flex items-center mb-6">
</li> <div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center mr-3">
@endforeach <svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor"
</ul> viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
@if(!empty($votesByYear)) d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4">
<h2 class="text-xl font-semibold mt-6 mb-4">Voteringar</h2> </path>
</svg>
</div>
<h2 class="text-2xl font-bold text-gray-900">Voteringar</h2>
</div>
<!-- Year tabs --> <!-- Year tabs -->
<div class="border-b border-gray-200 mb-4"> <div class="border-b border-gray-200 mb-4">
<nav class="-mb-px flex space-x-8"> <nav class="-mb-px flex space-x-8">
@foreach(array_keys($votesByYear) as $year) @foreach (array_keys($votesByYear) as $year)
<button <button wire:click="selectYear('{{ $year }}')"
wire:click="selectYear('{{ $year }}')"
class="cursor-pointer py-2 px-1 border-b-2 font-medium text-sm {{ $selectedYear == $year ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300' }}"> class="cursor-pointer py-2 px-1 border-b-2 font-medium text-sm {{ $selectedYear == $year ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300' }}">
{{ $year }} {{ $year }}
</button> </button>
@@ -121,75 +227,84 @@
</nav> </nav>
</div> </div>
@if($selectedYear && isset($votesByYear[$selectedYear])) @if ($selectedYear && isset($votesByYear[$selectedYear]))
<!-- Voting Statistics Chart --> <!-- Voting Statistics Chart -->
<div class="mb-8 bg-white p-6 rounded-lg shadow border"> <div class="mb-8 bg-gray-200 p-6 rounded-lg shadow border">
<h3 class="text-lg font-semibold mb-4">Röststatistik för {{ $selectedYear }}</h3> @if (!empty($this->votingStatistics))
@if(!empty($this->votingStatistics))
<div class="flex flex-col lg:flex-row gap-6"> <div class="flex flex-col lg:flex-row gap-6">
<div class="lg:w-1/2"> <div style="height: 23rem;">
<livewire:livewire-pie-chart <livewire:livewire-pie-chart :pie-chart-model="$this->pieChartModel"
:pie-chart-model="$this->pieChartModel" key="{{ 'pie-chart-' . $selectedYear }}" />
key="{{ 'pie-chart-'.$selectedYear }}"
/>
</div> </div>
<div class="lg:w-1/2"> <div class="lg:w-1/2 my-auto">
<div class="space-y-2"> <div class="space-y-2">
@foreach($this->votingStatistics as $voteType => $count) @php($totalVotes = array_sum($this->votingStatistics))
@foreach ($this->votingStatistics as $voteType => $count)
<div class="flex justify-between items-center p-3 bg-gray-50 rounded"> <div class="flex justify-between items-center p-3 bg-gray-50 rounded">
<span class="font-medium">{{ $voteType }}</span> <span class="text-black font-medium">{{ $voteType }}</span>
<span class="text-lg font-bold">{{ $count }}</span> <span class="text-black text-lg font-bold">{{ $count }}
({{ round(($count / $totalVotes) * 100, 2) }}%)</span>
</div> </div>
@endforeach @endforeach
<div class="flex justify-between items-center p-3 bg-blue-50 rounded border-t-2 border-blue-500"> <div
<span class="font-bold">Totalt antal voteringar</span> class="flex justify-between items-center p-3 bg-blue-50 rounded border-t-2 border-blue-500">
<span class="text-lg font-bold">{{ array_sum($this->votingStatistics) }}</span> <span class="text-black font-bold">Totalt antal voteringar</span>
<span
class="text-black text-lg font-bold">{{ array_sum($this->votingStatistics) }}</span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@else @else
<p class="text-gray-500">Ingen röststatistik tillgänglig för detta år.</p> <p class="text-gray-500">Ingen voteringsstatistik tillgänglig för detta år.</p>
@endif @endif
</div> </div>
@endif @endif
<!-- Votes table --> <!-- Votes table -->
@if($selectedYear && isset($votesByYear[$selectedYear])) @if ($selectedYear && isset($votesByYear[$selectedYear]))
<div class="overflow-x-auto" style="overflow-y: auto; display: block; max-height: 400px;"> <div class="overflow-x-auto" style="overflow-y: auto; display: block; max-height: 400px;">
<table class="min-w-full bg-white border border-gray-200"> <table class="min-w-full bg-white border border-gray-200">
<thead class="bg-gray-50 sticky top-0"> <thead class="bg-gray-50 sticky top-0">
<tr> <tr>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Datum</th> <th
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Beteckning</th> class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Punkt</th> Datum</th>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Röst</th> <th
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Avser</th> class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Votering</th> Beteckning</th>
<th
class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Punkt</th>
<th
class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Röst</th>
</tr> </tr>
</thead> </thead>
<tbody class="divide-y divide-gray-200"> <tbody class="divide-y divide-gray-100">
@foreach($votesByYear[$selectedYear] as $vote) @foreach ($votesByYear[$selectedYear] as $vote)
<tr class="hover:bg-gray-50 bg-gray-300"> <tr class="bg-gray-200">
<td class="px-4 py-2 text-sm text-gray-900"> <td class="px-4 py-2 text-sm text-gray-900">
{{ Carbon\Carbon::parse($vote->systemdatum)->format('Y-m-d') }} {{ Carbon\Carbon::parse($vote->systemdatum)->format('Y-m-d') }}
</td> </td>
<td class="px-4 py-2 text-sm"> <td class="px-4 py-2 text-sm">
<a href="{{ $vote->votering_url_xml }}" class="text-blue-600 hover:underline" target="_blank"> <a href="{{ $vote->votering_url_xml }}"
class="text-blue-600 hover:underline" target="_blank">
{{ $vote->beteckning }} {{ $vote->beteckning }}
</a> </a>
</td> </td>
<td class="px-4 py-2 text-sm text-gray-900">{{ $vote->punkt }}</td> <td class="px-4 py-2 text-sm text-gray-900">{{ $vote->punkt }}</td>
<td class="px-4 py-2 text-sm"> <td class="px-4 py-2 text-sm">
<span class="inline-flex px-2 py-1 text-xs font-semibold rounded-full <span
{{ $vote->rost === 'Ja' ? 'bg-green-100 text-green-800' : class="inline-flex px-2 py-1 text-xs font-semibold rounded-full
($vote->rost === 'Nej' ? 'bg-red-100 text-red-800' : {{ $vote->rost === 'Ja'
'bg-gray-100 text-gray-800') }}"> ? 'bg-green-100 text-green-800'
: ($vote->rost === 'Nej'
? 'bg-red-100 text-red-800'
: 'bg-gray-100 text-gray-800') }}">
{{ $vote->rost }} {{ $vote->rost }}
</span> </span>
</td> </td>
<td class="px-4 py-2 text-sm text-gray-900">{{ $vote->avser }}</td>
<td class="px-4 py-2 text-sm text-gray-900">{{ $vote->votering }}</td>
</tr> </tr>
@endforeach @endforeach
</tbody> </tbody>
@@ -198,11 +313,38 @@
@endif @endif
@endif @endif
</div> </div>
<!-- Biography Section -->
<div class="bg-white rounded-lg shadow-md border border-gray-200 p-6 mb-8">
<div class="flex items-center mb-6">
<div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center mr-3">
<svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.746 0 3.332.477 4.5 1.253v13C19.832 18.477 18.246 18 16.5 18c-1.746 0-3.332.477-4.5 1.253">
</path>
</svg>
</div>
<h2 class="text-2xl font-bold text-gray-900">Biografi</h2>
</div>
<div class="space-y-4">
@foreach (collect($person->personuppgift->uppgift ?? [])->where('typ', 'biografi') as $bio)
<div class="bg-gray-50 rounded-lg p-4">
<div class="font-semibold text-gray-900 mb-2">{{ $bio->kod }}</div>
<div class="text-gray-700">
{{ is_array($bio->uppgift) ? implode(', ', $bio->uppgift) : $bio->uppgift }}</div>
</div>
@endforeach
</div>
</div>
@else
<div class="bg-white rounded-lg shadow-md border border-gray-200 p-8 text-center">
<svg class="w-16 h-16 text-gray-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
<h3 class="text-lg font-medium text-gray-900 mb-2">Person inte hittad</h3>
<p class="text-gray-600">Personen kunde inte hittas i databasen.</p>
</div> </div>
@else
<div class="text-red-600">Personen kunde inte hittas.</div>
@endif @endif
<div class="mt-10 text-sm text-gray-500"> </div>
Källa: Sveriges riksdag (<a href="https://riksdagen.se/sv/" class="text-blue-600 underline" target="_blank">riksdagen.se</a>)
</div>
</div> </div>

View File

@@ -7,15 +7,14 @@ use App\Livewire\Settings\TwoFactor;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use Laravel\Fortify\Features; use Laravel\Fortify\Features;
use App\Livewire\HomePage;
use App\Livewire\Person\Search as PersonSearch; use App\Livewire\Person\Search as PersonSearch;
use App\Livewire\Person\Show as PersonShow; use App\Livewire\Person\Show as PersonShow;
Route::get('/', function () { Route::get('/', HomePage::class)->name('home');
return view('welcome');
})->name('home');
Route::get('/person', PersonSearch::class)->name('person.search'); Route::get('/ledamot', PersonSearch::class)->name('person.search');
Route::get('/person/{personId}', PersonShow::class)->name('person.show'); Route::get('/ledamot/{personId}', PersonShow::class)->name('person.show');
Route::view('dashboard', 'dashboard') Route::view('dashboard', 'dashboard')
->middleware(['auth', 'verified']) ->middleware(['auth', 'verified'])