Add new models and page for motions
This commit is contained in:
13
.prettierrc
Normal file
13
.prettierrc
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"plugins": ["prettier-plugin-blade"],
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": ["*.blade.php"],
|
||||||
|
"options": {
|
||||||
|
"parser": "blade"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"singleQuote": true,
|
||||||
|
"tabWidth": 4
|
||||||
|
}
|
||||||
93
app/Console/Commands/ImportRiksdagData.php
Normal file
93
app/Console/Commands/ImportRiksdagData.php
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Jobs\ImportRiksdagDataJob;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
|
class ImportRiksdagData extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*/
|
||||||
|
protected $signature = 'riksdag:import
|
||||||
|
{file? : The path to the JSON file to import}
|
||||||
|
{--url= : URL to download ZIP file from}
|
||||||
|
{--queue : Run the import job in the background queue}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*/
|
||||||
|
protected $description = 'Import Riksdag data from a JSON file or download and process a ZIP file from URL';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$filePath = $this->argument('file');
|
||||||
|
$url = $this->option('url');
|
||||||
|
|
||||||
|
if (! $filePath && ! $url) {
|
||||||
|
$this->error('Either provide a file path or use --url option');
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($url) {
|
||||||
|
// Process ZIP from URL
|
||||||
|
$this->info("Starting ZIP download and import from: {$url}");
|
||||||
|
|
||||||
|
if ($this->option('queue')) {
|
||||||
|
ImportRiksdagDataJob::dispatch($url, true);
|
||||||
|
$this->info('ZIP import job has been queued. Check queue workers for progress.');
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
$job = new ImportRiksdagDataJob($url, true);
|
||||||
|
$job->handle();
|
||||||
|
$this->info('ZIP import completed successfully!');
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->error('ZIP import failed: '.$e->getMessage());
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Process single file
|
||||||
|
if (! file_exists($filePath)) {
|
||||||
|
$this->error("File not found: {$filePath}");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate JSON format
|
||||||
|
$jsonContent = file_get_contents($filePath);
|
||||||
|
$testDecode = json_decode($jsonContent, true);
|
||||||
|
|
||||||
|
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||||
|
$this->error('Invalid JSON format: '.json_last_error_msg());
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info("Starting import from: {$filePath}");
|
||||||
|
|
||||||
|
if ($this->option('queue')) {
|
||||||
|
ImportRiksdagDataJob::dispatch($filePath, false);
|
||||||
|
$this->info('Import job has been queued. Check queue workers for progress.');
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
$job = new ImportRiksdagDataJob($filePath, false);
|
||||||
|
$job->handle();
|
||||||
|
$this->info('Import completed successfully!');
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->error('Import failed: '.$e->getMessage());
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
562
app/Jobs/ImportRiksdagDataJob.php
Normal file
562
app/Jobs/ImportRiksdagDataJob.php
Normal file
@@ -0,0 +1,562 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Models\DokAktivitet;
|
||||||
|
use App\Models\DokBilaga;
|
||||||
|
use App\Models\DokForslag;
|
||||||
|
use App\Models\DokIntressent;
|
||||||
|
use App\Models\DokReferens;
|
||||||
|
use App\Models\Dokument;
|
||||||
|
use App\Models\DokUppgift;
|
||||||
|
use App\Models\Organ;
|
||||||
|
use App\Models\Person;
|
||||||
|
use App\Models\PersonUppdrag;
|
||||||
|
use App\Models\PersonUppgift;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use ZipArchive;
|
||||||
|
|
||||||
|
class ImportRiksdagDataJob implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
protected $url;
|
||||||
|
|
||||||
|
protected $isUrl;
|
||||||
|
|
||||||
|
protected $filePath;
|
||||||
|
|
||||||
|
public function __construct(string $urlOrPath, bool $isUrl = false)
|
||||||
|
{
|
||||||
|
$this->url = $urlOrPath;
|
||||||
|
$this->isUrl = $isUrl;
|
||||||
|
$this->filePath = $urlOrPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if ($this->isUrl) {
|
||||||
|
$this->processZipFromUrl();
|
||||||
|
} else {
|
||||||
|
$this->processSingleFile($this->filePath);
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Error in ImportRiksdagDataJob: '.$e->getMessage());
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processZipFromUrl()
|
||||||
|
{
|
||||||
|
Log::info('Starting download from: '.$this->url);
|
||||||
|
|
||||||
|
// Download the ZIP file
|
||||||
|
$response = Http::timeout(300)->get($this->url);
|
||||||
|
|
||||||
|
if (! $response->successful()) {
|
||||||
|
throw new \Exception('Failed to download ZIP file from: '.$this->url);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create temporary directory
|
||||||
|
$tempDir = storage_path('app/temp/riksdag_import_'.time());
|
||||||
|
$zipPath = $tempDir.'/download.zip';
|
||||||
|
|
||||||
|
if (! is_dir($tempDir)) {
|
||||||
|
mkdir($tempDir, 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save ZIP file
|
||||||
|
file_put_contents($zipPath, $response->body());
|
||||||
|
Log::info('ZIP file downloaded to: '.$zipPath);
|
||||||
|
|
||||||
|
// Extract ZIP file
|
||||||
|
$extractPath = $tempDir.'/extracted';
|
||||||
|
$this->extractZipFile($zipPath, $extractPath);
|
||||||
|
|
||||||
|
// Process all JSON files in extracted directory
|
||||||
|
$this->processJsonFiles($extractPath);
|
||||||
|
|
||||||
|
// Clean up temporary files
|
||||||
|
$this->cleanupTempDirectory($tempDir);
|
||||||
|
|
||||||
|
Log::info('ZIP processing completed successfully');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function extractZipFile($zipPath, $extractPath)
|
||||||
|
{
|
||||||
|
$zip = new ZipArchive;
|
||||||
|
$result = $zip->open($zipPath);
|
||||||
|
|
||||||
|
if ($result !== true) {
|
||||||
|
throw new \Exception('Failed to open ZIP file: '.$zipPath.' (Error code: '.$result.')');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! is_dir($extractPath)) {
|
||||||
|
mkdir($extractPath, 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$zip->extractTo($extractPath);
|
||||||
|
$zip->close();
|
||||||
|
|
||||||
|
Log::info('ZIP file extracted to: '.$extractPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processJsonFiles($directory)
|
||||||
|
{
|
||||||
|
$jsonFiles = glob($directory.'/*.json');
|
||||||
|
|
||||||
|
if (empty($jsonFiles)) {
|
||||||
|
// Check subdirectories
|
||||||
|
$subdirs = glob($directory.'/*', GLOB_ONLYDIR);
|
||||||
|
foreach ($subdirs as $subdir) {
|
||||||
|
$jsonFiles = array_merge($jsonFiles, glob($subdir.'/*.json'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::info('Found '.count($jsonFiles).' JSON files to process');
|
||||||
|
|
||||||
|
foreach ($jsonFiles as $jsonFile) {
|
||||||
|
Log::info('Processing file: '.basename($jsonFile));
|
||||||
|
$this->processSingleFile($jsonFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function cleanupTempDirectory($tempDir)
|
||||||
|
{
|
||||||
|
$this->deleteDirectory($tempDir);
|
||||||
|
Log::info('Temporary directory cleaned up: '.$tempDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function deleteDirectory($dir)
|
||||||
|
{
|
||||||
|
if (! is_dir($dir)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$files = array_diff(scandir($dir), ['.', '..']);
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$path = $dir.'/'.$file;
|
||||||
|
is_dir($path) ? $this->deleteDirectory($path) : unlink($path);
|
||||||
|
}
|
||||||
|
rmdir($dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processSingleFile($filePath)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$jsonContent = file_get_contents($filePath);
|
||||||
|
$data = json_decode($jsonContent, true);
|
||||||
|
|
||||||
|
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||||
|
throw new \Exception('Invalid JSON format: '.json_last_error_msg());
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::beginTransaction();
|
||||||
|
|
||||||
|
// Handle new JSON structure with dokumentstatus wrapper
|
||||||
|
if (isset($data['dokumentstatus'])) {
|
||||||
|
$this->processDocumentStatus($data['dokumentstatus']);
|
||||||
|
}
|
||||||
|
// Legacy support for old structure
|
||||||
|
elseif (isset($data['dokumentlista'])) {
|
||||||
|
$this->importDokumentData($data['dokumentlista']);
|
||||||
|
} elseif (isset($data['personlista'])) {
|
||||||
|
$this->importPersonData($data['personlista']);
|
||||||
|
} elseif (isset($data['organlista'])) {
|
||||||
|
$this->importOrganData($data['organlista']);
|
||||||
|
}
|
||||||
|
// Handle single document structure
|
||||||
|
elseif (isset($data['dokument'])) {
|
||||||
|
$this->importSingleDokument($data['dokument']);
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::commit();
|
||||||
|
Log::info('Successfully imported data from: '.$filePath);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
DB::rollBack();
|
||||||
|
Log::error("Error importing data from {$filePath}: ".$e->getMessage());
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processDocumentStatus($dokumentStatus)
|
||||||
|
{
|
||||||
|
// Process the main document
|
||||||
|
if (isset($dokumentStatus['dokument'])) {
|
||||||
|
$this->processDokument($dokumentStatus['dokument']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get hangar_id for related data processing
|
||||||
|
$hangarId = $dokumentStatus['dokument']['hangar_id'] ?? null;
|
||||||
|
|
||||||
|
if (! $hangarId) {
|
||||||
|
throw new \Exception('No hangar_id found in document data');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process document proposals (forslag)
|
||||||
|
if (isset($dokumentStatus['dokforslag']['forslag']) && is_array($dokumentStatus['dokforslag']['forslag'])) {
|
||||||
|
$this->processForslag($hangarId, $dokumentStatus['dokforslag']['forslag']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process document activities (aktivitet)
|
||||||
|
if (isset($dokumentStatus['dokaktivitet']['aktivitet']) && is_array($dokumentStatus['dokaktivitet']['aktivitet'])) {
|
||||||
|
$this->processAktiviteter($hangarId, $dokumentStatus['dokaktivitet']['aktivitet']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process document interested parties (intressent)
|
||||||
|
if (isset($dokumentStatus['dokintressent']['intressent']) && is_array($dokumentStatus['dokintressent']['intressent'])) {
|
||||||
|
$this->processIntressenter($hangarId, $dokumentStatus['dokintressent']['intressent']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process document information (uppgift)
|
||||||
|
if (isset($dokumentStatus['dokuppgift']['uppgift']) && is_array($dokumentStatus['dokuppgift']['uppgift'])) {
|
||||||
|
$this->processUppgifter($hangarId, $dokumentStatus['dokuppgift']['uppgift']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process document attachments (bilaga)
|
||||||
|
if (isset($dokumentStatus['dokbilaga']['bilaga']) && is_array($dokumentStatus['dokbilaga']['bilaga'])) {
|
||||||
|
$this->processBilagor($hangarId, $dokumentStatus['dokbilaga']['bilaga']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process document references (referens)
|
||||||
|
if (isset($dokumentStatus['dokreferens']['referens']) && is_array($dokumentStatus['dokreferens']['referens'])) {
|
||||||
|
$this->processReferenser($hangarId, $dokumentStatus['dokreferens']['referens']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function importDokumentData($dokumentData)
|
||||||
|
{
|
||||||
|
$documents = isset($dokumentData['dokument']) ? $dokumentData['dokument'] : [];
|
||||||
|
|
||||||
|
// Handle both single document and array of documents
|
||||||
|
if (! is_array($documents) || (isset($documents['hangar_id']) && ! is_numeric(array_keys($documents)[0]))) {
|
||||||
|
$documents = [$documents];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($documents as $dokData) {
|
||||||
|
$this->processDokument($dokData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processDokument($dokData)
|
||||||
|
{
|
||||||
|
// Create main document
|
||||||
|
$dokument = Dokument::updateOrCreate(
|
||||||
|
['dok_id' => $dokData['dok_id'] ?? null],
|
||||||
|
[
|
||||||
|
'hangar_id' => $dokData['hangar_id'] ?? null,
|
||||||
|
'rm' => $dokData['rm'] ?? null,
|
||||||
|
'beteckning' => $dokData['beteckning'] ?? null,
|
||||||
|
'typ' => $dokData['typ'] ?? null,
|
||||||
|
'subtyp' => $dokData['subtyp'] ?? null,
|
||||||
|
'doktyp' => $dokData['doktyp'] ?? null,
|
||||||
|
'typrubrik' => $dokData['typrubrik'] ?? null,
|
||||||
|
'dokumentnamn' => $dokData['dokumentnamn'] ?? null,
|
||||||
|
'debattnamn' => $dokData['debattnamn'] ?? null,
|
||||||
|
'tempbeteckning' => $dokData['tempbeteckning'] ?? null,
|
||||||
|
'organ' => $dokData['organ'] ?? null,
|
||||||
|
'mottagare' => $dokData['mottagare'] ?? null,
|
||||||
|
'nummer' => $dokData['nummer'] ?? null,
|
||||||
|
'slutnummer' => $dokData['slutnummer'] ?? null,
|
||||||
|
'datum' => isset($dokData['datum']) ? $this->parseDate($dokData['datum']) : null,
|
||||||
|
'systemdatum' => isset($dokData['systemdatum']) ? $this->parseDate($dokData['systemdatum']) : null,
|
||||||
|
'publicerad' => isset($dokData['publicerad']) ? $this->parseDate($dokData['publicerad']) : null,
|
||||||
|
'titel' => $dokData['titel'] ?? null,
|
||||||
|
'subtitel' => $dokData['subtitel'] ?? null,
|
||||||
|
'status' => $dokData['status'] ?? null,
|
||||||
|
'htmlformat' => $dokData['htmlformat'] ?? null,
|
||||||
|
'relaterat_id' => $dokData['relaterat_id'] ?? null,
|
||||||
|
'source' => $dokData['source'] ?? null,
|
||||||
|
'sourceid' => $dokData['sourceid'] ?? null,
|
||||||
|
'dokument_url_text' => $dokData['dokument_url_text'] ?? null,
|
||||||
|
'dokument_url_html' => $dokData['dokument_url_html'] ?? null,
|
||||||
|
'dokumentstatus_url_xml' => $dokData['dokumentstatus_url_xml'] ?? null,
|
||||||
|
'utskottsforslag_url_xml' => $dokData['utskottsforslag_url_xml'] ?? null,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Process related data
|
||||||
|
if (isset($dokData['aktivitet']) && is_array($dokData['aktivitet'])) {
|
||||||
|
$this->processAktiviteter($dokument->hangar_id, $dokData['aktivitet']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($dokData['intressent']) && is_array($dokData['intressent'])) {
|
||||||
|
$this->processIntressenter($dokument->hangar_id, $dokData['intressent']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($dokData['bilaga']) && is_array($dokData['bilaga'])) {
|
||||||
|
$this->processBilagor($dokument->hangar_id, $dokData['bilaga']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($dokData['forslag']) && is_array($dokData['forslag'])) {
|
||||||
|
$this->processForslag($dokument->hangar_id, $dokData['forslag']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($dokData['uppgift']) && is_array($dokData['uppgift'])) {
|
||||||
|
$this->processUppgifter($dokument->hangar_id, $dokData['uppgift']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($dokData['referens']) && is_array($dokData['referens'])) {
|
||||||
|
$this->processReferenser($dokument->hangar_id, $dokData['referens']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processAktiviteter($hangarId, $aktiviteter)
|
||||||
|
{
|
||||||
|
foreach ($aktiviteter as $aktivitet) {
|
||||||
|
DokAktivitet::updateOrCreate(
|
||||||
|
[
|
||||||
|
'hangar_id' => $hangarId,
|
||||||
|
'kod' => $aktivitet['kod'] ?? null,
|
||||||
|
'datum' => isset($aktivitet['datum']) ? $this->parseDate($aktivitet['datum']) : null,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'namn' => $aktivitet['namn'] ?? null,
|
||||||
|
'status' => $aktivitet['status'] ?? null,
|
||||||
|
'ordning' => $aktivitet['ordning'] ?? null,
|
||||||
|
'process' => $aktivitet['process'] ?? null,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processIntressenter($hangarId, $intressenter)
|
||||||
|
{
|
||||||
|
foreach ($intressenter as $intressent) {
|
||||||
|
dump($intressent);
|
||||||
|
DokIntressent::updateOrCreate(
|
||||||
|
[
|
||||||
|
'hangar_id' => $hangarId,
|
||||||
|
'intressent_id' => $intressent['intressent_id'] ?? null,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'namn' => $intressent['namn'] ?? null,
|
||||||
|
'partibet' => $intressent['partibet'] ?? null,
|
||||||
|
'ordning' => $intressent['ordning'] ?? null,
|
||||||
|
'roll' => $intressent['roll'] ?? null,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processBilagor($hangarId, $bilagor)
|
||||||
|
{
|
||||||
|
foreach ($bilagor as $bilaga) {
|
||||||
|
DokBilaga::updateOrCreate(
|
||||||
|
[
|
||||||
|
'hangar_id' => $hangarId,
|
||||||
|
'dok_id' => $bilaga['dok_id'] ?? null,
|
||||||
|
'filnamn' => $bilaga['filnamn'] ?? null,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'titel' => $bilaga['titel'] ?? null,
|
||||||
|
'subtitel' => $bilaga['subtitel'] ?? null,
|
||||||
|
'filstorlek' => $bilaga['filstorlek'] ?? null,
|
||||||
|
'filtyp' => $bilaga['filtyp'] ?? null,
|
||||||
|
'fil_url' => $bilaga['fil_url'] ?? null,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processForslag($hangarId, $forslag)
|
||||||
|
{
|
||||||
|
foreach ($forslag as $forslagItem) {
|
||||||
|
DokForslag::updateOrCreate(
|
||||||
|
[
|
||||||
|
'hangar_id' => $hangarId,
|
||||||
|
'nummer' => $forslagItem['nummer'] ?? null,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'beteckning' => $forslagItem['beteckning'] ?? null,
|
||||||
|
'lydelse' => $forslagItem['lydelse'] ?? null,
|
||||||
|
'lydelse2' => $forslagItem['lydelse2'] ?? null,
|
||||||
|
'utskottet' => $forslagItem['utskottet'] ?? null,
|
||||||
|
'kammaren' => $forslagItem['kammaren'] ?? null,
|
||||||
|
'behandlas_i' => $forslagItem['behandlas_i'] ?? null,
|
||||||
|
'behandlas_i_punkt' => $forslagItem['behandlas_i_punkt'] ?? null,
|
||||||
|
'kammarbeslutstyp' => $forslagItem['kammarbeslutstyp'] ?? null,
|
||||||
|
'intressent' => $forslagItem['intressent'] ?? null,
|
||||||
|
'avsnitt' => $forslagItem['avsnitt'] ?? null,
|
||||||
|
'grundforfattning' => $forslagItem['grundforfattning'] ?? null,
|
||||||
|
'andringsforfattning' => $forslagItem['andringsforfattning'] ?? null,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processUppgifter($hangarId, $uppgifter)
|
||||||
|
{
|
||||||
|
foreach ($uppgifter as $uppgift) {
|
||||||
|
DokUppgift::updateOrCreate(
|
||||||
|
[
|
||||||
|
'hangar_id' => $hangarId,
|
||||||
|
'kod' => $uppgift['kod'] ?? null,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'namn' => $uppgift['namn'] ?? null,
|
||||||
|
'text' => $uppgift['text'] ?? null,
|
||||||
|
'dok_id' => $uppgift['dok_id'] ?? null,
|
||||||
|
'systemdatum' => isset($uppgift['systemdatum']) ? $this->parseDate($uppgift['systemdatum']) : null,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processReferenser($hangarId, $referenser)
|
||||||
|
{
|
||||||
|
foreach ($referenser as $referens) {
|
||||||
|
DokReferens::updateOrCreate(
|
||||||
|
[
|
||||||
|
'hangar_id' => $hangarId,
|
||||||
|
'referenstyp' => $referens['referenstyp'] ?? null,
|
||||||
|
'ref_dok_id' => $referens['ref_dok_id'] ?? null,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'uppgift' => $referens['uppgift'] ?? null,
|
||||||
|
'ref_dok_typ' => $referens['ref_dok_typ'] ?? null,
|
||||||
|
'ref_dok_rm' => $referens['ref_dok_rm'] ?? null,
|
||||||
|
'ref_dok_bet' => $referens['ref_dok_bet'] ?? null,
|
||||||
|
'ref_dok_titel' => $referens['ref_dok_titel'] ?? null,
|
||||||
|
'ref_dok_subtitel' => $referens['ref_dok_subtitel'] ?? null,
|
||||||
|
'ref_dok_subtyp' => $referens['ref_dok_subtyp'] ?? null,
|
||||||
|
'ref_dok_dokumentnamn' => $referens['ref_dok_dokumentnamn'] ?? null,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function importPersonData($personData)
|
||||||
|
{
|
||||||
|
$persons = isset($personData['person']) ? $personData['person'] : [];
|
||||||
|
|
||||||
|
// Handle both single person and array of persons
|
||||||
|
if (! is_array($persons) || (isset($persons['intressent_id']) && ! is_numeric(array_keys($persons)[0]))) {
|
||||||
|
$persons = [$persons];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($persons as $personInfo) {
|
||||||
|
$this->processPerson($personInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processPerson($personInfo)
|
||||||
|
{
|
||||||
|
$person = Person::updateOrCreate(
|
||||||
|
['intressent_id' => $personInfo['intressent_id'] ?? null],
|
||||||
|
[
|
||||||
|
'född_år' => $personInfo['fodd_ar'] ?? $personInfo['född_år'] ?? null,
|
||||||
|
'kön' => $personInfo['kon'] ?? $personInfo['kön'] ?? null,
|
||||||
|
'efternamn' => $personInfo['efternamn'] ?? null,
|
||||||
|
'tilltalsnamn' => $personInfo['tilltalsnamn'] ?? null,
|
||||||
|
'sorteringsnamn' => $personInfo['sorteringsnamn'] ?? null,
|
||||||
|
'iort' => $personInfo['iort'] ?? null,
|
||||||
|
'parti' => $personInfo['parti'] ?? null,
|
||||||
|
'valkrets' => $personInfo['valkrets'] ?? null,
|
||||||
|
'status' => $personInfo['status'] ?? null,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Process person assignments
|
||||||
|
if (isset($personInfo['personuppdrag']['uppdrag']) && is_array($personInfo['personuppdrag']['uppdrag'])) {
|
||||||
|
$this->processPersonUppdrag($person->intressent_id, $personInfo['personuppdrag']['uppdrag']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process person information
|
||||||
|
if (isset($personInfo['personuppgift']['uppgift']) && is_array($personInfo['personuppgift']['uppgift'])) {
|
||||||
|
$this->processPersonUppgift($person->intressent_id, $personInfo['personuppgift']['uppgift']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processPersonUppdrag($intressentId, $uppdragList)
|
||||||
|
{
|
||||||
|
foreach ($uppdragList as $uppdrag) {
|
||||||
|
PersonUppdrag::updateOrCreate(
|
||||||
|
[
|
||||||
|
'intressent_id' => $intressentId,
|
||||||
|
'organ_kod' => $uppdrag['organ_kod'] ?? null,
|
||||||
|
'roll_kod' => $uppdrag['roll_kod'] ?? null,
|
||||||
|
'ordningsnummer' => $uppdrag['ordningsnummer'] ?? null,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'status' => $uppdrag['status'] ?? null,
|
||||||
|
'typ' => $uppdrag['typ'] ?? null,
|
||||||
|
'from' => isset($uppdrag['from']) ? $this->parseDate($uppdrag['from']) : null,
|
||||||
|
'tom' => isset($uppdrag['tom']) ? $this->parseDate($uppdrag['tom']) : null,
|
||||||
|
'uppgift' => $uppdrag['uppgift'] ?? null,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processPersonUppgift($intressentId, $uppgiftList)
|
||||||
|
{
|
||||||
|
foreach ($uppgiftList as $uppgift) {
|
||||||
|
PersonUppgift::updateOrCreate(
|
||||||
|
[
|
||||||
|
'intressent_id' => $intressentId,
|
||||||
|
'uppgift_kod' => $uppgift['kod'] ?? null,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'uppgift' => $uppgift['uppgift'] ?? null,
|
||||||
|
'uppgift_typ' => $uppgift['typ'] ?? null,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function importOrganData($organData)
|
||||||
|
{
|
||||||
|
$organs = isset($organData['organ']) ? $organData['organ'] : [];
|
||||||
|
|
||||||
|
// Handle both single organ and array of organs
|
||||||
|
if (! is_array($organs) || (isset($organs['id']) && ! is_numeric(array_keys($organs)[0]))) {
|
||||||
|
$organs = [$organs];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($organs as $organInfo) {
|
||||||
|
Organ::updateOrCreate(
|
||||||
|
['id' => $organInfo['id'] ?? null],
|
||||||
|
[
|
||||||
|
'kod' => $organInfo['kod'] ?? null,
|
||||||
|
'namn' => $organInfo['namn'] ?? null,
|
||||||
|
'typ' => $organInfo['typ'] ?? null,
|
||||||
|
'status' => $organInfo['status'] ?? null,
|
||||||
|
'sortering' => $organInfo['sortering'] ?? null,
|
||||||
|
'namn_en' => $organInfo['namn_en'] ?? null,
|
||||||
|
'domän' => $organInfo['doman'] ?? $organInfo['domän'] ?? null,
|
||||||
|
'beskrivning' => $organInfo['beskrivning'] ?? null,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function importSingleDokument($dokument)
|
||||||
|
{
|
||||||
|
$this->processDokument($dokument);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function parseDate($dateString)
|
||||||
|
{
|
||||||
|
if (empty($dateString)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return \Carbon\Carbon::parse($dateString);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::warning("Could not parse date: {$dateString}");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
146
app/Livewire/Motion/Search.php
Normal file
146
app/Livewire/Motion/Search.php
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Motion;
|
||||||
|
|
||||||
|
use App\Enums\Parties as PartyEnum;
|
||||||
|
use App\Services\RiksdagenService;
|
||||||
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Livewire\Attributes\Computed;
|
||||||
|
use Livewire\Attributes\Url;
|
||||||
|
use Livewire\Component;
|
||||||
|
use Livewire\WithPagination;
|
||||||
|
|
||||||
|
class Search extends Component
|
||||||
|
{
|
||||||
|
use WithPagination;
|
||||||
|
|
||||||
|
#[Url]
|
||||||
|
public $query = '';
|
||||||
|
|
||||||
|
#[Url]
|
||||||
|
public $party = '';
|
||||||
|
|
||||||
|
#[Url]
|
||||||
|
public $dateInterval = '';
|
||||||
|
|
||||||
|
private $paginator;
|
||||||
|
|
||||||
|
public $loading = false;
|
||||||
|
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->searchMotions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updatedQuery()
|
||||||
|
{
|
||||||
|
$this->resetPage();
|
||||||
|
$this->searchMotions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updatedParty()
|
||||||
|
{
|
||||||
|
$this->resetPage();
|
||||||
|
$this->searchMotions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updatedDateInterval()
|
||||||
|
{
|
||||||
|
$this->resetPage();
|
||||||
|
$this->searchMotions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function searchMotions()
|
||||||
|
{
|
||||||
|
if (empty($this->query) && empty($this->party) && empty($this->dateInterval)) {
|
||||||
|
$this->paginator = null;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->loading = true;
|
||||||
|
|
||||||
|
$cacheKey = 'motions_'.md5($this->query.$this->party.$this->dateInterval.$this->getPage());
|
||||||
|
|
||||||
|
$result = Cache::remember($cacheKey, 60 * 5, function () {
|
||||||
|
return app(RiksdagenService::class)->searchMotions(
|
||||||
|
query: $this->query,
|
||||||
|
party: $this->party,
|
||||||
|
dateInterval: $this->dateInterval,
|
||||||
|
page: $this->getPage()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
$motions = $result->original->dokumentlista->dokument ?? [];
|
||||||
|
$totalResults = (int) ($result->original->dokumentlista->{'@traffar'} ?? 0);
|
||||||
|
$perPage = 20; // Default items per page from Riksdag API
|
||||||
|
$currentPage = $this->getPage();
|
||||||
|
|
||||||
|
$this->paginator = new LengthAwarePaginator(
|
||||||
|
items: collect($motions),
|
||||||
|
total: $totalResults,
|
||||||
|
perPage: $perPage,
|
||||||
|
currentPage: $currentPage,
|
||||||
|
options: [
|
||||||
|
'path' => request()->url(),
|
||||||
|
'pageName' => 'page',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Computed()]
|
||||||
|
public function motions()
|
||||||
|
{
|
||||||
|
return $this->paginator ? collect($this->paginator->items()) : collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Computed()]
|
||||||
|
public function totalResults()
|
||||||
|
{
|
||||||
|
return $this->paginator ? $this->paginator->total() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clearFilters()
|
||||||
|
{
|
||||||
|
$this->query = '';
|
||||||
|
$this->party = '';
|
||||||
|
$this->dateInterval = '';
|
||||||
|
$this->resetPage();
|
||||||
|
$this->searchMotions();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Computed()]
|
||||||
|
public function parties()
|
||||||
|
{
|
||||||
|
return collect(PartyEnum::cases())->mapWithKeys(function ($party) {
|
||||||
|
return [$party->value => $party->label()];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Computed()]
|
||||||
|
public function dateIntervals()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'2025/26' => '2025/26',
|
||||||
|
'2024/25' => '2024/25',
|
||||||
|
'2023/24' => '2023/24',
|
||||||
|
'2022/23' => '2022/23',
|
||||||
|
'2021/22' => '2021/22',
|
||||||
|
'2020/21' => '2020/21',
|
||||||
|
'2019/20' => '2019/20',
|
||||||
|
'2018/19' => '2018/19',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
$this->searchMotions();
|
||||||
|
|
||||||
|
return view('livewire.motion.search', [
|
||||||
|
'paginatedMotions' => $this->paginator,
|
||||||
|
])->title('Sök Motioner - Riksdagen App');
|
||||||
|
}
|
||||||
|
}
|
||||||
71
app/Livewire/Motion/Show.php
Normal file
71
app/Livewire/Motion/Show.php
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Motion;
|
||||||
|
|
||||||
|
use App\Services\RiksdagenService;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Livewire\Attributes\Computed;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class Show extends Component
|
||||||
|
{
|
||||||
|
public $motionId;
|
||||||
|
|
||||||
|
public $motion;
|
||||||
|
|
||||||
|
private RiksdagenService $service;
|
||||||
|
|
||||||
|
public function mount($motionId)
|
||||||
|
{
|
||||||
|
$this->motionId = $motionId;
|
||||||
|
$this->service = app(RiksdagenService::class);
|
||||||
|
|
||||||
|
$result = Cache::remember('motion_'.$motionId, 24 * 60 * 60, function () use ($motionId) {
|
||||||
|
return $this->service->getMotion($motionId);
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->motion = $result->original->dokumentlista->dokument[0] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Computed()]
|
||||||
|
public function riksdagenUrl()
|
||||||
|
{
|
||||||
|
return 'https://www.riksdagen.se/sv/dokument-lagar/dokument/'.$this->motionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Computed()]
|
||||||
|
public function authors()
|
||||||
|
{
|
||||||
|
if (! $this->motion || ! isset($this->motion->dokintressent->intressent)) {
|
||||||
|
return collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
$intressenter = $this->motion->dokintressent->intressent;
|
||||||
|
if (! is_array($intressenter)) {
|
||||||
|
$intressenter = [$intressenter];
|
||||||
|
}
|
||||||
|
|
||||||
|
return collect($intressenter)->where('roll', 'undertecknare');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Computed()]
|
||||||
|
public function attachments()
|
||||||
|
{
|
||||||
|
if (! $this->motion || ! isset($this->motion->filbilaga->fil)) {
|
||||||
|
return collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
$files = $this->motion->filbilaga->fil;
|
||||||
|
if (! is_array($files)) {
|
||||||
|
$files = [$files];
|
||||||
|
}
|
||||||
|
|
||||||
|
return collect($files);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.motion.show')
|
||||||
|
->title(($this->motion->titel ?? 'Motion').' - Riksdagen App');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,30 +2,35 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Person;
|
namespace App\Livewire\Person;
|
||||||
|
|
||||||
use Livewire\Component;
|
|
||||||
use App\Services\RiksdagenService;
|
|
||||||
use App\Enums\Parties;
|
use App\Enums\Parties;
|
||||||
|
use App\Services\RiksdagenService;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
class Search extends Component
|
class Search extends Component
|
||||||
{
|
{
|
||||||
public $firstName = '';
|
public $firstName = '';
|
||||||
|
|
||||||
public $lastName = '';
|
public $lastName = '';
|
||||||
|
|
||||||
public $party = '';
|
public $party = '';
|
||||||
|
|
||||||
public $results = [];
|
public $results = [];
|
||||||
|
|
||||||
public $parties = [];
|
public $parties = [];
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->parties = collect(Parties::cases())->sortBy(fn($party) => $party->label())->toArray();
|
$this->parties = collect(Parties::cases())->sortBy(fn ($party) => $party->label())->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function search()
|
public function search()
|
||||||
{
|
{
|
||||||
$service = app(RiksdagenService::class);
|
$service = app(RiksdagenService::class);
|
||||||
|
|
||||||
$this->results = $service->searchPerson(
|
$this->results = $service->searchPerson(
|
||||||
firstName: $this->firstName,
|
firstName: $this->firstName,
|
||||||
lastName: $this->lastName,
|
lastName: $this->lastName,
|
||||||
party: $this->party
|
party: $this->party,
|
||||||
)->original;
|
)->original;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,12 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Person;
|
namespace App\Livewire\Person;
|
||||||
|
|
||||||
use Livewire\Component;
|
|
||||||
use App\Services\RiksdagenService;
|
use App\Services\RiksdagenService;
|
||||||
use Livewire\Attributes\Computed;
|
|
||||||
use Asantibanez\LivewireCharts\Models\PieChartModel;
|
use Asantibanez\LivewireCharts\Models\PieChartModel;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Livewire\Attributes\Computed;
|
||||||
use Livewire\Attributes\Lazy;
|
use Livewire\Attributes\Lazy;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
#[Lazy()]
|
#[Lazy()]
|
||||||
class Show extends Component
|
class Show extends Component
|
||||||
@@ -17,9 +18,15 @@ class Show extends Component
|
|||||||
|
|
||||||
public $votes = [];
|
public $votes = [];
|
||||||
|
|
||||||
|
public $motions = [];
|
||||||
|
|
||||||
public $votesByYear = [];
|
public $votesByYear = [];
|
||||||
|
|
||||||
public $selectedYear;
|
public $motionsByYear = [];
|
||||||
|
|
||||||
|
public $votesSelectedYear;
|
||||||
|
|
||||||
|
public $motionsSelectedYear;
|
||||||
|
|
||||||
public $selectedUppdragTab = 'current';
|
public $selectedUppdragTab = 'current';
|
||||||
|
|
||||||
@@ -27,47 +34,87 @@ class Show extends Component
|
|||||||
|
|
||||||
public $previousUppdrag = [];
|
public $previousUppdrag = [];
|
||||||
|
|
||||||
|
private RiksdagenService $service;
|
||||||
|
|
||||||
public function mount($personId)
|
public function mount($personId)
|
||||||
{
|
{
|
||||||
$this->personId = $personId;
|
$this->personId = $personId;
|
||||||
$service = app(RiksdagenService::class);
|
$this->service = app(RiksdagenService::class);
|
||||||
$result = $service->searchPerson(mp_id: $personId);
|
$result = Cache::remember('person_'.$personId, 24 * 60 * 60, function () use ($personId) {
|
||||||
|
return $this->service->searchPerson(mp_id: $personId);
|
||||||
|
});
|
||||||
$this->person = $result->original->personlista->person ?? null;
|
$this->person = $result->original->personlista->person ?? null;
|
||||||
|
|
||||||
$this->getPersonVotes();
|
$this->getPersonVotes();
|
||||||
|
$this->getPersonMotions();
|
||||||
$this->groupUppdrag();
|
$this->groupUppdrag();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Computed()]
|
#[Computed()]
|
||||||
public function riksdagenUrl()
|
public function riksdagenUrl()
|
||||||
{
|
{
|
||||||
return "https://www.riksdagen.se/sv/ledamoter-partier/ledamot/" . $this->person->tilltalsnamn . "-" . $this->person->efternamn . "_" . $this->personId;
|
return 'https://www.riksdagen.se/sv/ledamoter-partier/ledamot/'.$this->person->tilltalsnamn.'-'.$this->person->efternamn.'_'.$this->personId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPersonVotes()
|
public function getPersonVotes()
|
||||||
{
|
{
|
||||||
$service = app(RiksdagenService::class);
|
$result = Cache::remember('person_votes_'.$this->personId, 24 * 60 * 60, function () {
|
||||||
$result = $service->searchVotes(mp_id: $this->personId);
|
return $this->service->searchVotes(mp_id: $this->personId);
|
||||||
|
});
|
||||||
|
|
||||||
$votesList = $result->original->voteringlista->votering ?? [];
|
$votesList = $result->original->voteringlista->votering ?? [];
|
||||||
|
|
||||||
// Group votes by year (from rm field like 2025/26)
|
// Group votes by "rm" field (e.g., 2024/25)
|
||||||
foreach ($votesList as $vote) {
|
foreach ($votesList as $vote) {
|
||||||
$year = explode('/', $vote->rm)[0]; // Extract year from rm like "2025/26"
|
$rm = $vote->rm;
|
||||||
if (!isset($this->votesByYear[$year])) {
|
if (! isset($this->votesByYear[$rm])) {
|
||||||
$this->votesByYear[$year] = [];
|
$this->votesByYear[$rm] = [];
|
||||||
}
|
}
|
||||||
$this->votesByYear[$year][] = $vote;
|
$this->votesByYear[$rm][] = $vote;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set default selected year to the most recent
|
// Set default selected year to the most recent
|
||||||
if (!empty($this->votesByYear)) {
|
if (! empty($this->votesByYear)) {
|
||||||
$this->selectedYear = max(array_keys($this->votesByYear));
|
// Sort keys as strings (e.g., 2024/25, 2023/24, ...)
|
||||||
|
$years = array_keys($this->votesByYear);
|
||||||
|
rsort($years, SORT_STRING);
|
||||||
|
$this->votesSelectedYear = $years[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function selectYear($year)
|
public function getPersonMotions()
|
||||||
{
|
{
|
||||||
$this->selectedYear = $year;
|
$result = Cache::remember('person_motions_'.$this->personId, 24 * 60 * 60, function () {
|
||||||
|
return $this->service->getPersonMotions(mp_id: $this->personId);
|
||||||
|
});
|
||||||
|
$motionsList = $result->original->dokumentlista->dokument ?? [];
|
||||||
|
|
||||||
|
// Group votes by "rm" field (e.g., 2024/25)
|
||||||
|
foreach ($motionsList as $motion) {
|
||||||
|
$rm = $motion->rm;
|
||||||
|
if (! isset($this->motionsByYear[$rm])) {
|
||||||
|
$this->motionsByYear[$rm] = [];
|
||||||
|
}
|
||||||
|
$this->motionsByYear[$rm][] = $motion;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set default selected year to the most recent
|
||||||
|
if (! empty($this->motionsByYear)) {
|
||||||
|
// Sort keys as strings (e.g., 2024/25, 2023/24, ...)
|
||||||
|
$years = array_keys($this->motionsByYear);
|
||||||
|
rsort($years, SORT_STRING);
|
||||||
|
$this->motionsSelectedYear = $years[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function selectVotesYear($year)
|
||||||
|
{
|
||||||
|
$this->votesSelectedYear = $year;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function selectMotionsYear($year)
|
||||||
|
{
|
||||||
|
$this->motionsSelectedYear = $year;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function selectUppdragTab($tab)
|
public function selectUppdragTab($tab)
|
||||||
@@ -77,7 +124,7 @@ class Show extends Component
|
|||||||
|
|
||||||
public function groupUppdrag()
|
public function groupUppdrag()
|
||||||
{
|
{
|
||||||
if (!$this->person || !isset($this->person->personuppdrag->uppdrag)) {
|
if (! $this->person || ! isset($this->person->personuppdrag->uppdrag)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,11 +145,11 @@ class Show extends Component
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sort by date (most recent first)
|
// Sort by date (most recent first)
|
||||||
usort($this->currentUppdrag, function($a, $b) {
|
usort($this->currentUppdrag, function ($a, $b) {
|
||||||
return \Carbon\Carbon::parse($b->from)->timestamp - \Carbon\Carbon::parse($a->from)->timestamp;
|
return \Carbon\Carbon::parse($b->from)->timestamp - \Carbon\Carbon::parse($a->from)->timestamp;
|
||||||
});
|
});
|
||||||
|
|
||||||
usort($this->previousUppdrag, function($a, $b) {
|
usort($this->previousUppdrag, function ($a, $b) {
|
||||||
return \Carbon\Carbon::parse($b->tom ?: $b->from)->timestamp - \Carbon\Carbon::parse($a->tom ?: $a->from)->timestamp;
|
return \Carbon\Carbon::parse($b->tom ?: $b->from)->timestamp - \Carbon\Carbon::parse($a->tom ?: $a->from)->timestamp;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -110,16 +157,16 @@ class Show extends Component
|
|||||||
#[Computed()]
|
#[Computed()]
|
||||||
public function votingStatistics()
|
public function votingStatistics()
|
||||||
{
|
{
|
||||||
if (!$this->selectedYear || !isset($this->votesByYear[$this->selectedYear])) {
|
if (! $this->votesSelectedYear || ! isset($this->votesByYear[$this->votesSelectedYear])) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
$votes = $this->votesByYear[$this->selectedYear];
|
$votes = $this->votesByYear[$this->votesSelectedYear];
|
||||||
$statistics = [];
|
$statistics = [];
|
||||||
|
|
||||||
foreach ($votes as $vote) {
|
foreach ($votes as $vote) {
|
||||||
$voteType = $vote->rost;
|
$voteType = $vote->rost;
|
||||||
if (!isset($statistics[$voteType])) {
|
if (! isset($statistics[$voteType])) {
|
||||||
$statistics[$voteType] = 0;
|
$statistics[$voteType] = 0;
|
||||||
}
|
}
|
||||||
$statistics[$voteType]++;
|
$statistics[$voteType]++;
|
||||||
@@ -133,8 +180,8 @@ class Show extends Component
|
|||||||
{
|
{
|
||||||
$statistics = $this->votingStatistics;
|
$statistics = $this->votingStatistics;
|
||||||
|
|
||||||
$pieChart = (new PieChartModel())
|
$pieChart = (new PieChartModel)
|
||||||
->setTitle('Voteringsstatistik för ' . $this->selectedYear)
|
->setTitle('Voteringsstatistik för '.$this->votesSelectedYear)
|
||||||
->setAnimated(true)
|
->setAnimated(true)
|
||||||
->withDataLabels();
|
->withDataLabels();
|
||||||
|
|
||||||
|
|||||||
20
app/Models/Anforande.php
Normal file
20
app/Models/Anforande.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Anforande extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'anforande';
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
public function dokument()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Dokument::class, 'dok_hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function person()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Person::class, 'intressent_id', 'intressent_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
20
app/Models/Debatt.php
Normal file
20
app/Models/Debatt.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Debatt extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'debatt';
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
public function dokument()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Dokument::class, 'hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function person()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Person::class, 'intressent_id', 'intressent_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
27
app/Models/DokAktivitet.php
Normal file
27
app/Models/DokAktivitet.php
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class DokAktivitet extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'dokaktivitet';
|
||||||
|
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'hangar_id',
|
||||||
|
'kod',
|
||||||
|
'datum',
|
||||||
|
'namn',
|
||||||
|
'status',
|
||||||
|
'ordning',
|
||||||
|
'process',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function dokument()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Dokument::class, 'hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
28
app/Models/DokBilaga.php
Normal file
28
app/Models/DokBilaga.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class DokBilaga extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'dokbilaga';
|
||||||
|
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'hangar_id',
|
||||||
|
'dok_id',
|
||||||
|
'filnamn',
|
||||||
|
'titel',
|
||||||
|
'subtitel',
|
||||||
|
'filstorlek',
|
||||||
|
'filtyp',
|
||||||
|
'fil_url',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function dokument()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Dokument::class, 'hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
34
app/Models/DokForslag.php
Normal file
34
app/Models/DokForslag.php
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class DokForslag extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'dokforslag';
|
||||||
|
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'hangar_id',
|
||||||
|
'nummer',
|
||||||
|
'beteckning',
|
||||||
|
'lydelse',
|
||||||
|
'lydelse2',
|
||||||
|
'utskottet',
|
||||||
|
'kammaren',
|
||||||
|
'behandlas_i',
|
||||||
|
'behandlas_i_punkt',
|
||||||
|
'kammarbeslutstyp',
|
||||||
|
'intressent',
|
||||||
|
'avsnitt',
|
||||||
|
'grundforfattning',
|
||||||
|
'andringsforfattning',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function dokument()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Dokument::class, 'hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
31
app/Models/DokIntressent.php
Normal file
31
app/Models/DokIntressent.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class DokIntressent extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'dokintressent';
|
||||||
|
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'hangar_id',
|
||||||
|
'intressent_id',
|
||||||
|
'namn',
|
||||||
|
'partibet',
|
||||||
|
'ordning',
|
||||||
|
'roll',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function dokument()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Dokument::class, 'hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function person()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Person::class, 'intressent_id', 'intressent_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
15
app/Models/DokMotforslag.php
Normal file
15
app/Models/DokMotforslag.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class DokMotforslag extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'dokmotforslag';
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
public function dokument()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Dokument::class, 'hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
31
app/Models/DokReferens.php
Normal file
31
app/Models/DokReferens.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class DokReferens extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'dokreferens';
|
||||||
|
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'hangar_id',
|
||||||
|
'referenstyp',
|
||||||
|
'ref_dok_id',
|
||||||
|
'uppgift',
|
||||||
|
'ref_dok_typ',
|
||||||
|
'ref_dok_rm',
|
||||||
|
'ref_dok_bet',
|
||||||
|
'ref_dok_titel',
|
||||||
|
'ref_dok_subtitel',
|
||||||
|
'ref_dok_subtyp',
|
||||||
|
'ref_dok_dokumentnamn',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function dokument()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Dokument::class, 'hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
30
app/Models/DokUppgift.php
Normal file
30
app/Models/DokUppgift.php
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class DokUppgift extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'dokuppgift';
|
||||||
|
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'hangar_id',
|
||||||
|
'kod',
|
||||||
|
'namn',
|
||||||
|
'text',
|
||||||
|
'dok_id',
|
||||||
|
'systemdatum',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'systemdatum' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function dokument()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Dokument::class, 'hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
15
app/Models/DokUtskottsforslag.php
Normal file
15
app/Models/DokUtskottsforslag.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class DokUtskottsforslag extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'dokutskottsforslag';
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
public function dokument()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Dokument::class, 'hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
102
app/Models/Dokument.php
Normal file
102
app/Models/Dokument.php
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Dokument extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'dokument';
|
||||||
|
|
||||||
|
protected $primaryKey = 'hangar_id';
|
||||||
|
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'hangar_id',
|
||||||
|
'dok_id',
|
||||||
|
'rm',
|
||||||
|
'beteckning',
|
||||||
|
'typ',
|
||||||
|
'subtyp',
|
||||||
|
'doktyp',
|
||||||
|
'typrubrik',
|
||||||
|
'dokumentnamn',
|
||||||
|
'debattnamn',
|
||||||
|
'tempbeteckning',
|
||||||
|
'organ',
|
||||||
|
'mottagare',
|
||||||
|
'nummer',
|
||||||
|
'slutnummer',
|
||||||
|
'datum',
|
||||||
|
'systemdatum',
|
||||||
|
'publicerad',
|
||||||
|
'titel',
|
||||||
|
'subtitel',
|
||||||
|
'status',
|
||||||
|
'htmlformat',
|
||||||
|
'relaterat_id',
|
||||||
|
'source',
|
||||||
|
'sourceid',
|
||||||
|
'dokument_url_text',
|
||||||
|
'dokument_url_html',
|
||||||
|
'dokumentstatus_url_xml',
|
||||||
|
'utskottsforslag_url_xml',
|
||||||
|
'html',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function utskottsforslag()
|
||||||
|
{
|
||||||
|
return $this->hasMany(DokUtskottsforslag::class, 'hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function motforslag()
|
||||||
|
{
|
||||||
|
return $this->hasMany(DokMotforslag::class, 'hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function aktiviteter()
|
||||||
|
{
|
||||||
|
return $this->hasMany(DokAktivitet::class, 'hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function intressenter()
|
||||||
|
{
|
||||||
|
return $this->hasMany(DokIntressent::class, 'hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function forslag()
|
||||||
|
{
|
||||||
|
return $this->hasMany(DokForslag::class, 'hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function uppgifter()
|
||||||
|
{
|
||||||
|
return $this->hasMany(DokUppgift::class, 'hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function bilagor()
|
||||||
|
{
|
||||||
|
return $this->hasMany(DokBilaga::class, 'hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function referenser()
|
||||||
|
{
|
||||||
|
return $this->hasMany(DokReferens::class, 'hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function debatter()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Debatt::class, 'hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function voteringar()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Votering::class, 'hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function anforanden()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Anforande::class, 'dok_hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
31
app/Models/Organ.php
Normal file
31
app/Models/Organ.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Organ extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'organ';
|
||||||
|
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'id',
|
||||||
|
'kod',
|
||||||
|
'namn',
|
||||||
|
'typ',
|
||||||
|
'status',
|
||||||
|
'sortering',
|
||||||
|
'namn_en',
|
||||||
|
'domän',
|
||||||
|
'beskrivning',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function personUppdrag()
|
||||||
|
{
|
||||||
|
return $this->hasMany(PersonUppdrag::class, 'organ_kod', 'kod');
|
||||||
|
}
|
||||||
|
}
|
||||||
61
app/Models/Person.php
Normal file
61
app/Models/Person.php
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Person extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'person';
|
||||||
|
|
||||||
|
protected $primaryKey = 'intressent_id';
|
||||||
|
|
||||||
|
protected $keyType = 'string';
|
||||||
|
|
||||||
|
public $incrementing = false;
|
||||||
|
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'intressent_id',
|
||||||
|
'född_år',
|
||||||
|
'kön',
|
||||||
|
'efternamn',
|
||||||
|
'tilltalsnamn',
|
||||||
|
'sorteringsnamn',
|
||||||
|
'iort',
|
||||||
|
'parti',
|
||||||
|
'valkrets',
|
||||||
|
'status',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function uppdrag()
|
||||||
|
{
|
||||||
|
return $this->hasMany(PersonUppdrag::class, 'intressent_id', 'intressent_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function uppgifter()
|
||||||
|
{
|
||||||
|
return $this->hasMany(PersonUppgift::class, 'intressent_id', 'intressent_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function voteringar()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Votering::class, 'intressent_id', 'intressent_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function anforanden()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Anforande::class, 'intressent_id', 'intressent_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function debatter()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Debatt::class, 'intressent_id', 'intressent_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dokIntressenter()
|
||||||
|
{
|
||||||
|
return $this->hasMany(DokIntressent::class, 'intressent_id', 'intressent_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
44
app/Models/PersonUppdrag.php
Normal file
44
app/Models/PersonUppdrag.php
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class PersonUppdrag extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'personuppdrag';
|
||||||
|
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'intressent_id',
|
||||||
|
'organ_kod',
|
||||||
|
'roll_kod',
|
||||||
|
'ordningsnummer',
|
||||||
|
'status',
|
||||||
|
'typ',
|
||||||
|
'from',
|
||||||
|
'tom',
|
||||||
|
'uppgift',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'from' => 'datetime',
|
||||||
|
'tom' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function person()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Person::class, 'intressent_id', 'intressent_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function organ()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Organ::class, 'organ_kod', 'kod');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function roll()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Roll::class, 'roll_kod', 'kod');
|
||||||
|
}
|
||||||
|
}
|
||||||
24
app/Models/PersonUppgift.php
Normal file
24
app/Models/PersonUppgift.php
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class PersonUppgift extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'personuppgift';
|
||||||
|
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'intressent_id',
|
||||||
|
'uppgift_kod',
|
||||||
|
'uppgift',
|
||||||
|
'uppgift_typ',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function person()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Person::class, 'intressent_id', 'intressent_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
31
app/Models/Planering.php
Normal file
31
app/Models/Planering.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Planering extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'planering';
|
||||||
|
protected $primaryKey = 'nyckel';
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'datum' => 'datetime',
|
||||||
|
'publicerad' => 'datetime',
|
||||||
|
'uppdaterad' => 'datetime',
|
||||||
|
'wn_expires' => 'datetime',
|
||||||
|
'timestamp' => 'datetime',
|
||||||
|
'slutdatum' => 'datetime',
|
||||||
|
'webbtvlive' => 'boolean',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function person()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Person::class, 'intressent_id', 'intressent_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function mottagare()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Person::class, 'mottagare_id', 'intressent_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
16
app/Models/Riksmote.php
Normal file
16
app/Models/Riksmote.php
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Riksmote extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'riksmote';
|
||||||
|
protected $primaryKey = 'pk';
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'start' => 'datetime',
|
||||||
|
'slut' => 'datetime',
|
||||||
|
];
|
||||||
|
}
|
||||||
16
app/Models/Roll.php
Normal file
16
app/Models/Roll.php
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Roll extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'roll';
|
||||||
|
protected $primaryKey = 'pk';
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
public function personUppdrag()
|
||||||
|
{
|
||||||
|
return $this->hasMany(PersonUppdrag::class, 'roll_kod', 'kod');
|
||||||
|
}
|
||||||
|
}
|
||||||
20
app/Models/Votering.php
Normal file
20
app/Models/Votering.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Votering extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'votering';
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
public function dokument()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Dokument::class, 'hangar_id', 'hangar_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function person()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Person::class, 'intressent_id', 'intressent_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,8 +30,8 @@ class RiksdagenService
|
|||||||
'enamn' => $lastName,
|
'enamn' => $lastName,
|
||||||
'utformat' => 'json',
|
'utformat' => 'json',
|
||||||
'sort' => 'sorteringsnamn',
|
'sort' => 'sorteringsnamn',
|
||||||
'sortorder' => 'asc'
|
'sortorder' => 'asc',
|
||||||
]
|
],
|
||||||
])->getBody()->getContents();
|
])->getBody()->getContents();
|
||||||
|
|
||||||
$data = json_decode($response);
|
$data = json_decode($response);
|
||||||
@@ -50,8 +50,86 @@ class RiksdagenService
|
|||||||
'rm' => $date,
|
'rm' => $date,
|
||||||
'parti' => $party,
|
'parti' => $party,
|
||||||
'utformat' => 'json',
|
'utformat' => 'json',
|
||||||
'sz' => '500',
|
'sz' => '3000',
|
||||||
]
|
],
|
||||||
|
])->getBody()->getContents();
|
||||||
|
|
||||||
|
$data = json_decode($response);
|
||||||
|
|
||||||
|
return response()->json($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPersonMotions(
|
||||||
|
string $mp_id,
|
||||||
|
string $date = '',
|
||||||
|
): JsonResponse {
|
||||||
|
$response = $this->http->get('dokumentlista/', [
|
||||||
|
'query' => [
|
||||||
|
'iid' => $mp_id,
|
||||||
|
'rm' => $date,
|
||||||
|
'doktyp' => 'mot',
|
||||||
|
'utformat' => 'json',
|
||||||
|
],
|
||||||
|
])->getBody()->getContents();
|
||||||
|
|
||||||
|
$data = json_decode($response);
|
||||||
|
|
||||||
|
return response()->json($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPartyMotions(
|
||||||
|
string $party,
|
||||||
|
string $date = '',
|
||||||
|
|
||||||
|
): JsonResponse {
|
||||||
|
$response = $this->http->get('dokumentlista/', [
|
||||||
|
'query' => [
|
||||||
|
'parti' => $party,
|
||||||
|
'rm' => $date,
|
||||||
|
'doktyp' => 'mot',
|
||||||
|
'utformat' => 'json',
|
||||||
|
],
|
||||||
|
])->getBody()->getContents();
|
||||||
|
|
||||||
|
$data = json_decode($response);
|
||||||
|
|
||||||
|
return response()->json($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function searchMotions(
|
||||||
|
string $query = '',
|
||||||
|
string $party = '',
|
||||||
|
string $dateInterval = '',
|
||||||
|
int $page = 1
|
||||||
|
): JsonResponse {
|
||||||
|
$response = $this->http->get('dokumentlista/', [
|
||||||
|
'query' => array_filter([
|
||||||
|
'sok' => $query,
|
||||||
|
'parti' => $party,
|
||||||
|
'rm' => $dateInterval,
|
||||||
|
'doktyp' => 'mot',
|
||||||
|
'utformat' => 'json',
|
||||||
|
'p' => $page,
|
||||||
|
]),
|
||||||
|
])->getBody()->getContents();
|
||||||
|
|
||||||
|
$data = json_decode($response);
|
||||||
|
|
||||||
|
return response()->json($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMotion(
|
||||||
|
string $bet,
|
||||||
|
string $tempbet,
|
||||||
|
string $nr,
|
||||||
|
): JsonResponse {
|
||||||
|
$response = $this->http->get('dokumentlista/', [
|
||||||
|
'query' => [
|
||||||
|
'bet' => $bet,
|
||||||
|
'tempbet' => $tempbet,
|
||||||
|
'nr' => $nr,
|
||||||
|
'utformat' => 'json',
|
||||||
|
],
|
||||||
])->getBody()->getContents();
|
])->getBody()->getContents();
|
||||||
|
|
||||||
$data = json_decode($response);
|
$data = json_decode($response);
|
||||||
|
|||||||
@@ -0,0 +1,340 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
// dokument
|
||||||
|
Schema::create('dokument', function (Blueprint $table) {
|
||||||
|
$table->integer('hangar_id');
|
||||||
|
$table->string('dok_id');
|
||||||
|
$table->string('rm');
|
||||||
|
$table->string('beteckning')->nullable();
|
||||||
|
$table->string('typ')->nullable();
|
||||||
|
$table->string('subtyp')->nullable();
|
||||||
|
$table->string('doktyp')->nullable();
|
||||||
|
$table->string('typrubrik')->nullable();
|
||||||
|
$table->string('dokumentnamn')->nullable();
|
||||||
|
$table->string('debattnamn')->nullable();
|
||||||
|
$table->string('tempbeteckning')->nullable();
|
||||||
|
$table->string('organ')->nullable();
|
||||||
|
$table->string('mottagare')->nullable();
|
||||||
|
$table->integer('nummer')->nullable();
|
||||||
|
$table->integer('slutnummer')->nullable();
|
||||||
|
$table->dateTime('datum')->nullable();
|
||||||
|
$table->dateTime('systemdatum')->nullable();
|
||||||
|
$table->dateTime('publicerad')->nullable();
|
||||||
|
$table->string('titel')->nullable();
|
||||||
|
$table->string('subtitel')->nullable();
|
||||||
|
$table->string('status')->nullable();
|
||||||
|
$table->string('htmlformat')->nullable();
|
||||||
|
$table->string('relaterat_id')->nullable();
|
||||||
|
$table->string('source')->nullable();
|
||||||
|
$table->string('sourceid')->nullable();
|
||||||
|
$table->string('dokument_url_text')->nullable();
|
||||||
|
$table->string('dokument_url_html')->nullable();
|
||||||
|
$table->string('dokumentstatus_url_xml')->nullable();
|
||||||
|
$table->string('utskottsforslag_url_xml')->nullable();
|
||||||
|
$table->text('html')->nullable();
|
||||||
|
});
|
||||||
|
// dokutskottsforslag
|
||||||
|
Schema::create('dokutskottsforslag', function (Blueprint $table) {
|
||||||
|
$table->integer('hangar_id');
|
||||||
|
$table->integer('punkt');
|
||||||
|
$table->string('beteckning', 50)->nullable();
|
||||||
|
$table->string('rubrik')->nullable();
|
||||||
|
$table->string('forslag')->nullable();
|
||||||
|
$table->text('forslag_del2')->nullable();
|
||||||
|
$table->string('beslutstyp')->nullable();
|
||||||
|
$table->string('beslut', 100)->nullable();
|
||||||
|
$table->integer('motforslag_nummer')->nullable();
|
||||||
|
$table->string('motforslag_partier')->nullable();
|
||||||
|
$table->string('votering_id')->nullable();
|
||||||
|
$table->string('votering_sammanfattning_html')->nullable();
|
||||||
|
$table->string('votering_ledamot_url_xml')->nullable();
|
||||||
|
$table->string('rm')->nullable();
|
||||||
|
$table->string('bet')->nullable();
|
||||||
|
$table->string('vinnare')->nullable();
|
||||||
|
});
|
||||||
|
// dokmotforslag
|
||||||
|
Schema::create('dokmotforslag', function (Blueprint $table) {
|
||||||
|
$table->integer('hangar_id');
|
||||||
|
$table->integer('nummer');
|
||||||
|
$table->string('rubrik')->nullable();
|
||||||
|
$table->text('forslag')->nullable();
|
||||||
|
$table->string('partier')->nullable();
|
||||||
|
$table->string('typ')->nullable();
|
||||||
|
$table->integer('utskottsforslag_punkt')->nullable();
|
||||||
|
$table->string('id', 50)->nullable();
|
||||||
|
});
|
||||||
|
// dokaktivitet
|
||||||
|
Schema::create('dokaktivitet', function (Blueprint $table) {
|
||||||
|
$table->integer('hangar_id');
|
||||||
|
$table->string('kod')->nullable();
|
||||||
|
$table->string('namn')->nullable();
|
||||||
|
$table->dateTime('datum')->nullable();
|
||||||
|
$table->string('status')->nullable();
|
||||||
|
$table->string('ordning')->nullable();
|
||||||
|
$table->string('process')->nullable();
|
||||||
|
});
|
||||||
|
// dokintressent
|
||||||
|
Schema::create('dokintressent', function (Blueprint $table) {
|
||||||
|
$table->integer('hangar_id');
|
||||||
|
$table->string('intressent_id');
|
||||||
|
$table->string('namn')->nullable();
|
||||||
|
$table->string('partibet')->nullable();
|
||||||
|
$table->integer('ordning')->nullable();
|
||||||
|
$table->string('roll')->nullable();
|
||||||
|
});
|
||||||
|
// dokforslag
|
||||||
|
Schema::create('dokforslag', function (Blueprint $table) {
|
||||||
|
$table->integer('hangar_id');
|
||||||
|
$table->integer('nummer')->nullable();
|
||||||
|
$table->string('beteckning')->nullable();
|
||||||
|
$table->string('lydelse', 500)->nullable();
|
||||||
|
$table->string('lydelse2')->nullable();
|
||||||
|
$table->string('utskottet')->nullable();
|
||||||
|
$table->string('kammaren')->nullable();
|
||||||
|
$table->string('behandlas_i')->nullable();
|
||||||
|
$table->string('behandlas_i_punkt')->nullable();
|
||||||
|
$table->string('kammarbeslutstyp')->nullable();
|
||||||
|
$table->string('intressent')->nullable();
|
||||||
|
$table->string('avsnitt')->nullable();
|
||||||
|
$table->string('grundforfattning')->nullable();
|
||||||
|
$table->string('andringsforfattning')->nullable();
|
||||||
|
});
|
||||||
|
// dokuppgift
|
||||||
|
Schema::create('dokuppgift', function (Blueprint $table) {
|
||||||
|
$table->integer('hangar_id');
|
||||||
|
$table->string('kod')->nullable();
|
||||||
|
$table->string('namn')->nullable();
|
||||||
|
$table->text('text')->nullable();
|
||||||
|
$table->string('dok_id')->nullable();
|
||||||
|
$table->dateTime('systemdatum')->nullable();
|
||||||
|
});
|
||||||
|
// dokbilaga
|
||||||
|
Schema::create('dokbilaga', function (Blueprint $table) {
|
||||||
|
$table->integer('hangar_id');
|
||||||
|
$table->string('dok_id')->nullable();
|
||||||
|
$table->string('titel')->nullable();
|
||||||
|
$table->string('subtitel')->nullable();
|
||||||
|
$table->string('filnamn')->nullable();
|
||||||
|
$table->integer('filstorlek')->nullable();
|
||||||
|
$table->string('filtyp')->nullable();
|
||||||
|
$table->string('fil_url')->nullable();
|
||||||
|
});
|
||||||
|
// dokreferens
|
||||||
|
Schema::create('dokreferens', function (Blueprint $table) {
|
||||||
|
$table->integer('hangar_id');
|
||||||
|
$table->string('referenstyp')->nullable();
|
||||||
|
$table->string('uppgift')->nullable();
|
||||||
|
$table->string('ref_dok_id')->nullable();
|
||||||
|
$table->string('ref_dok_typ')->nullable();
|
||||||
|
$table->string('ref_dok_rm')->nullable();
|
||||||
|
$table->string('ref_dok_bet')->nullable();
|
||||||
|
$table->string('ref_dok_titel')->nullable();
|
||||||
|
$table->string('ref_dok_subtitel')->nullable();
|
||||||
|
$table->string('ref_dok_subtyp')->nullable();
|
||||||
|
$table->string('ref_dok_dokumentnamn')->nullable();
|
||||||
|
});
|
||||||
|
// debatt
|
||||||
|
Schema::create('debatt', function (Blueprint $table) {
|
||||||
|
$table->integer('hangar_id');
|
||||||
|
$table->string('video_id')->nullable();
|
||||||
|
$table->string('video_url')->nullable();
|
||||||
|
$table->integer('startpos')->nullable();
|
||||||
|
$table->string('tumnagel')->nullable();
|
||||||
|
$table->string('tumnagel_stor')->nullable();
|
||||||
|
$table->string('anf_video_id')->nullable();
|
||||||
|
$table->integer('anf_hangar_id')->nullable();
|
||||||
|
$table->integer('anf_sekunder')->nullable();
|
||||||
|
$table->string('anf_klockslag')->nullable();
|
||||||
|
$table->dateTime('datumtid')->nullable();
|
||||||
|
$table->dateTime('anf_datum')->nullable();
|
||||||
|
$table->string('anf_typ')->nullable();
|
||||||
|
$table->string('anf_text')->nullable();
|
||||||
|
$table->string('anf_beteckning')->nullable();
|
||||||
|
$table->string('anf_nummer')->nullable();
|
||||||
|
$table->string('talare')->nullable();
|
||||||
|
$table->string('intressent_id')->nullable();
|
||||||
|
$table->string('parti')->nullable();
|
||||||
|
$table->string('anf_rm')->nullable();
|
||||||
|
});
|
||||||
|
// votering
|
||||||
|
Schema::create('votering', function (Blueprint $table) {
|
||||||
|
$table->string('rm');
|
||||||
|
$table->string('beteckning')->nullable();
|
||||||
|
$table->integer('hangar_id');
|
||||||
|
$table->string('votering_id')->nullable();
|
||||||
|
$table->integer('punkt')->nullable();
|
||||||
|
$table->string('namn')->nullable();
|
||||||
|
$table->string('intressent_id')->nullable();
|
||||||
|
$table->string('parti')->nullable();
|
||||||
|
$table->string('valkrets')->nullable();
|
||||||
|
$table->integer('valkretsnummer')->nullable();
|
||||||
|
$table->string('iort')->nullable();
|
||||||
|
$table->string('rost')->nullable();
|
||||||
|
$table->string('avser')->nullable();
|
||||||
|
$table->string('votering')->nullable();
|
||||||
|
$table->integer('banknummer')->nullable();
|
||||||
|
$table->string('fornamn')->nullable();
|
||||||
|
$table->string('efternamn')->nullable();
|
||||||
|
$table->string('kon')->nullable();
|
||||||
|
$table->integer('fodd')->nullable();
|
||||||
|
$table->dateTime('datum')->nullable();
|
||||||
|
});
|
||||||
|
// anforande
|
||||||
|
Schema::create('anforande', function (Blueprint $table) {
|
||||||
|
$table->integer('dok_hangar_id');
|
||||||
|
$table->string('dok_id', 50);
|
||||||
|
$table->string('dok_titel')->nullable();
|
||||||
|
$table->string('dok_rm', 20)->nullable();
|
||||||
|
$table->integer('dok_nummer')->nullable();
|
||||||
|
$table->dateTime('dok_datum')->nullable();
|
||||||
|
$table->string('avsnittsrubrik')->nullable();
|
||||||
|
$table->string('underrubrik')->nullable();
|
||||||
|
$table->string('kammaraktivitet', 250)->nullable();
|
||||||
|
$table->string('anforande_id', 50);
|
||||||
|
$table->integer('anforande_nummer')->nullable();
|
||||||
|
$table->string('talare', 250)->nullable();
|
||||||
|
$table->string('parti', 50)->nullable();
|
||||||
|
$table->text('anforandetext')->nullable();
|
||||||
|
$table->string('intressent_id', 50)->nullable();
|
||||||
|
$table->string('rel_dok_id', 50)->nullable();
|
||||||
|
$table->char('replik', 1)->nullable();
|
||||||
|
$table->dateTime('systemdatum')->nullable();
|
||||||
|
});
|
||||||
|
// person
|
||||||
|
Schema::create('person', function (Blueprint $table) {
|
||||||
|
$table->string('intressent_id', 20)->primary();
|
||||||
|
$table->smallInteger('född_år')->nullable();
|
||||||
|
$table->string('kön', 6)->nullable();
|
||||||
|
$table->string('efternamn', 50)->nullable();
|
||||||
|
$table->string('tilltalsnamn', 50)->nullable();
|
||||||
|
$table->string('sorteringsnamn', 80)->nullable();
|
||||||
|
$table->string('iort', 40)->nullable();
|
||||||
|
$table->string('parti', 40)->nullable();
|
||||||
|
$table->string('valkrets', 50)->nullable();
|
||||||
|
$table->string('status', 100)->nullable();
|
||||||
|
});
|
||||||
|
// personuppdrag
|
||||||
|
Schema::create('personuppdrag', function (Blueprint $table) {
|
||||||
|
$table->string('organ_kod', 20);
|
||||||
|
$table->string('roll_kod', 40);
|
||||||
|
$table->integer('ordningsnummer');
|
||||||
|
$table->string('status', 20)->nullable();
|
||||||
|
$table->string('typ', 20)->nullable();
|
||||||
|
$table->dateTime('from')->nullable();
|
||||||
|
$table->dateTime('tom')->nullable();
|
||||||
|
$table->string('uppgift', 500)->nullable();
|
||||||
|
$table->string('intressent_id', 50);
|
||||||
|
});
|
||||||
|
// personuppgift
|
||||||
|
Schema::create('personuppgift', function (Blueprint $table) {
|
||||||
|
$table->string('uppgift_kod', 50);
|
||||||
|
$table->text('uppgift')->nullable();
|
||||||
|
$table->string('uppgift_typ', 50)->nullable();
|
||||||
|
$table->string('intressent_id', 50);
|
||||||
|
});
|
||||||
|
// planering
|
||||||
|
Schema::create('planering', function (Blueprint $table) {
|
||||||
|
$table->integer('nyckel');
|
||||||
|
$table->string('id', 50);
|
||||||
|
$table->string('rm', 12)->nullable();
|
||||||
|
$table->string('typ', 40)->nullable();
|
||||||
|
$table->char('dokserie_id', 2)->nullable();
|
||||||
|
$table->string('subtyp', 40)->nullable();
|
||||||
|
$table->string('bet', 40)->nullable();
|
||||||
|
$table->string('tempbet', 40)->nullable();
|
||||||
|
$table->string('intressent', 80)->nullable();
|
||||||
|
$table->integer('nummer')->nullable();
|
||||||
|
$table->integer('slutnummer')->nullable();
|
||||||
|
$table->dateTime('datum')->nullable();
|
||||||
|
$table->dateTime('publicerad')->nullable();
|
||||||
|
$table->string('status', 40)->nullable();
|
||||||
|
$table->string('titel', 300)->nullable();
|
||||||
|
$table->string('subtitel', 255)->nullable();
|
||||||
|
$table->text('html')->nullable();
|
||||||
|
$table->text('toc')->nullable();
|
||||||
|
$table->string('refcss', 66)->nullable();
|
||||||
|
$table->string('url', 100)->nullable();
|
||||||
|
$table->dateTime('uppdaterad')->nullable();
|
||||||
|
$table->integer('storlek')->nullable();
|
||||||
|
$table->string('source', 20)->nullable();
|
||||||
|
$table->dateTime('wn_expires')->nullable();
|
||||||
|
$table->string('wn_cachekey', 50)->nullable();
|
||||||
|
$table->string('wn_status', 20)->nullable();
|
||||||
|
$table->string('wn_checksum', 40)->nullable();
|
||||||
|
$table->integer('wn_nid')->nullable();
|
||||||
|
$table->string('wn_RawUrl', 255)->nullable();
|
||||||
|
$table->string('wn_SourceID', 80)->nullable();
|
||||||
|
$table->dateTime('timestamp')->nullable();
|
||||||
|
$table->string('rel_id', 50)->nullable();
|
||||||
|
$table->string('klockslag', 10)->nullable();
|
||||||
|
$table->string('grupp', 20)->nullable();
|
||||||
|
$table->string('format', 20)->nullable();
|
||||||
|
$table->string('intressent_id', 13)->nullable();
|
||||||
|
$table->string('mottagare_id', 13)->nullable();
|
||||||
|
$table->string('mottagare', 80)->nullable();
|
||||||
|
$table->integer('hangar_id')->nullable();
|
||||||
|
$table->string('plats', 150)->nullable();
|
||||||
|
$table->dateTime('slutdatum')->nullable();
|
||||||
|
$table->tinyInteger('webbtvlive')->nullable();
|
||||||
|
});
|
||||||
|
// organ
|
||||||
|
Schema::create('organ', function (Blueprint $table) {
|
||||||
|
$table->integer('id')->primary();
|
||||||
|
$table->string('kod', 50)->nullable();
|
||||||
|
$table->string('namn', 100)->nullable();
|
||||||
|
$table->string('typ', 50)->nullable();
|
||||||
|
$table->string('status', 12)->nullable();
|
||||||
|
$table->integer('sortering')->nullable();
|
||||||
|
$table->string('namn_en', 100)->nullable();
|
||||||
|
$table->string('domän', 50)->nullable();
|
||||||
|
$table->string('beskrivning', 1000)->nullable();
|
||||||
|
});
|
||||||
|
// roll
|
||||||
|
Schema::create('roll', function (Blueprint $table) {
|
||||||
|
$table->integer('pk')->primary();
|
||||||
|
$table->string('kod', 50)->nullable();
|
||||||
|
$table->string('namn', 100)->nullable();
|
||||||
|
$table->integer('sort')->nullable();
|
||||||
|
});
|
||||||
|
// riksmote
|
||||||
|
Schema::create('riksmote', function (Blueprint $table) {
|
||||||
|
$table->integer('pk')->primary();
|
||||||
|
$table->string('riksmote', 20)->nullable();
|
||||||
|
$table->string('id', 3)->nullable();
|
||||||
|
$table->dateTime('start')->nullable();
|
||||||
|
$table->dateTime('slut')->nullable();
|
||||||
|
$table->string('mandatperiod', 20)->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('dokument');
|
||||||
|
Schema::dropIfExists('dokutskottsforslag');
|
||||||
|
Schema::dropIfExists('dokmotforslag');
|
||||||
|
Schema::dropIfExists('dokaktivitet');
|
||||||
|
Schema::dropIfExists('dokintressent');
|
||||||
|
Schema::dropIfExists('dokforslag');
|
||||||
|
Schema::dropIfExists('dokuppgift');
|
||||||
|
Schema::dropIfExists('dokbilaga');
|
||||||
|
Schema::dropIfExists('dokreferens');
|
||||||
|
Schema::dropIfExists('debatt');
|
||||||
|
Schema::dropIfExists('votering');
|
||||||
|
Schema::dropIfExists('anforande');
|
||||||
|
Schema::dropIfExists('person');
|
||||||
|
Schema::dropIfExists('personuppdrag');
|
||||||
|
Schema::dropIfExists('personuppgift');
|
||||||
|
Schema::dropIfExists('planering');
|
||||||
|
Schema::dropIfExists('organ');
|
||||||
|
Schema::dropIfExists('roll');
|
||||||
|
Schema::dropIfExists('riksmote');
|
||||||
|
}
|
||||||
|
};
|
||||||
33
package-lock.json
generated
33
package-lock.json
generated
@@ -13,6 +13,9 @@
|
|||||||
"tailwindcss": "^4.0.7",
|
"tailwindcss": "^4.0.7",
|
||||||
"vite": "^7.0.4"
|
"vite": "^7.0.4"
|
||||||
},
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"prettier-plugin-blade": "^2.1.21"
|
||||||
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rollup/rollup-linux-x64-gnu": "4.9.5",
|
"@rollup/rollup-linux-x64-gnu": "4.9.5",
|
||||||
"@tailwindcss/oxide-linux-x64-gnu": "^4.0.1",
|
"@tailwindcss/oxide-linux-x64-gnu": "^4.0.1",
|
||||||
@@ -2056,6 +2059,36 @@
|
|||||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/prettier": {
|
||||||
|
"version": "3.7.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz",
|
||||||
|
"integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"bin": {
|
||||||
|
"prettier": "bin/prettier.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prettier-plugin-blade": {
|
||||||
|
"version": "2.1.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier-plugin-blade/-/prettier-plugin-blade-2.1.21.tgz",
|
||||||
|
"integrity": "sha512-+BPBPvla/Ppr0MVrqMAO+FTwxpXUYo8zhQPIGC7psNuMbB24y84cGrJ4Uc02GHTQN0q8txeG4Y4MxyJWgOujyQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"prettier": ">=3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/proxy-from-env": {
|
"node_modules/proxy-from-env": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
|
|||||||
@@ -19,5 +19,8 @@
|
|||||||
"@rollup/rollup-linux-x64-gnu": "4.9.5",
|
"@rollup/rollup-linux-x64-gnu": "4.9.5",
|
||||||
"@tailwindcss/oxide-linux-x64-gnu": "^4.0.1",
|
"@tailwindcss/oxide-linux-x64-gnu": "^4.0.1",
|
||||||
"lightningcss-linux-x64-gnu": "^1.29.1"
|
"lightningcss-linux-x64-gnu": "^1.29.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"prettier-plugin-blade": "^2.1.21"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,30 +6,117 @@
|
|||||||
Riksdagen App
|
Riksdagen App
|
||||||
</h1>
|
</h1>
|
||||||
<p class="text-lg text-gray-600 max-w-2xl mx-auto">
|
<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
|
Utforska information om riksdagsledamöter, deras röster och
|
||||||
|
uppdrag i Sveriges riksdag
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Navigation Cards -->
|
<!-- Navigation Cards -->
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 max-w-6xl mx-auto">
|
<div
|
||||||
|
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 max-w-6xl mx-auto"
|
||||||
|
>
|
||||||
<!-- Person Search Card -->
|
<!-- Person Search Card -->
|
||||||
<a wire:navigate href="{{ route('person.search') }}" class="group">
|
<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="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="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">
|
<div
|
||||||
<svg class="w-6 h-6 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center mb-4 group-hover:bg-blue-200 transition-colors"
|
||||||
<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
|
||||||
|
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>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="text-xl font-semibold text-gray-900 mb-2">Ledamöter</h3>
|
<h3 class="text-xl font-semibold text-gray-900 mb-2">
|
||||||
|
Ledamöter
|
||||||
|
</h3>
|
||||||
<p class="text-gray-600 mb-4">
|
<p class="text-gray-600 mb-4">
|
||||||
Sök och utforska information om riksdagsledamöter, deras rösthistorik och uppdrag
|
Sök och utforska information om riksdagsledamöter,
|
||||||
|
deras rösthistorik och uppdrag
|
||||||
</p>
|
</p>
|
||||||
<div class="flex items-center text-blue-600 group-hover:text-blue-700">
|
<div
|
||||||
<span class="text-sm font-medium">Sök ledamöter</span>
|
class="flex items-center text-blue-600 group-hover:text-blue-700"
|
||||||
<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>
|
<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>
|
||||||
|
|
||||||
|
<!-- Motion Search Card -->
|
||||||
|
<a wire:navigate href="{{ route('motion.search') }}" class="group">
|
||||||
|
<div
|
||||||
|
class="bg-white rounded-lg h-full 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-green-100 rounded-lg flex items-center justify-center mb-4 group-hover:bg-green-200 transition-colors"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-6 h-6 text-green-600"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-xl font-semibold text-gray-900 mb-2">
|
||||||
|
Motioner
|
||||||
|
</h3>
|
||||||
|
<p class="text-gray-600 mb-4">
|
||||||
|
Sök bland motioner som lämnats till riksdagen av
|
||||||
|
ledamöterna
|
||||||
|
</p>
|
||||||
|
<div
|
||||||
|
class="flex items-center text-green-600 group-hover:text-green-700"
|
||||||
|
>
|
||||||
|
<span class="text-sm font-medium">
|
||||||
|
Sök motioner
|
||||||
|
</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>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -37,16 +124,33 @@
|
|||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- Placeholder Card 1 -->
|
<!-- Placeholder Card 1 -->
|
||||||
<div class="bg-white rounded-lg shadow-md border border-gray-200 overflow-hidden opacity-60">
|
<div
|
||||||
|
class="bg-white rounded-lg shadow-md border border-gray-200 overflow-hidden opacity-60"
|
||||||
|
>
|
||||||
<div class="p-6">
|
<div class="p-6">
|
||||||
<div class="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4">
|
<div
|
||||||
<svg class="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
class="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4"
|
||||||
<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
|
||||||
|
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>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="text-xl font-semibold text-gray-500 mb-2">Propositioner</h3>
|
<h3 class="text-xl font-semibold text-gray-500 mb-2">
|
||||||
|
Propositioner
|
||||||
|
</h3>
|
||||||
<p class="text-gray-400 mb-4">
|
<p class="text-gray-400 mb-4">
|
||||||
Sök och läs propositioner och andra dokument från riksdagen
|
Sök och läs propositioner och andra dokument från
|
||||||
|
riksdagen
|
||||||
</p>
|
</p>
|
||||||
<div class="flex items-center text-gray-400">
|
<div class="flex items-center text-gray-400">
|
||||||
<span class="text-sm font-medium">Kommer snart</span>
|
<span class="text-sm font-medium">Kommer snart</span>
|
||||||
@@ -55,14 +159,30 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Placeholder Card 2 -->
|
<!-- Placeholder Card 2 -->
|
||||||
<div class="bg-white rounded-lg shadow-md border border-gray-200 overflow-hidden opacity-60">
|
<div
|
||||||
|
class="bg-white rounded-lg shadow-md border border-gray-200 overflow-hidden opacity-60"
|
||||||
|
>
|
||||||
<div class="p-6">
|
<div class="p-6">
|
||||||
<div class="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4">
|
<div
|
||||||
<svg class="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
class="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4"
|
||||||
<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
|
||||||
|
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>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="text-xl font-semibold text-gray-500 mb-2">Statistik</h3>
|
<h3 class="text-xl font-semibold text-gray-500 mb-2">
|
||||||
|
Statistik
|
||||||
|
</h3>
|
||||||
<p class="text-gray-400 mb-4">
|
<p class="text-gray-400 mb-4">
|
||||||
Se röststatistik och analyser för partier och ledamöter
|
Se röststatistik och analyser för partier och ledamöter
|
||||||
</p>
|
</p>
|
||||||
@@ -72,33 +192,31 @@
|
|||||||
</div>
|
</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 -->
|
<!-- Placeholder Card 4 -->
|
||||||
<div class="bg-white rounded-lg shadow-md border border-gray-200 overflow-hidden opacity-60">
|
<div
|
||||||
|
class="bg-white rounded-lg shadow-md border border-gray-200 overflow-hidden opacity-60"
|
||||||
|
>
|
||||||
<div class="p-6">
|
<div class="p-6">
|
||||||
<div class="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4">
|
<div
|
||||||
<svg class="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
class="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4"
|
||||||
<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
|
||||||
|
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>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="text-xl font-semibold text-gray-500 mb-2">Partier</h3>
|
<h3 class="text-xl font-semibold text-gray-500 mb-2">
|
||||||
|
Partier
|
||||||
|
</h3>
|
||||||
<p class="text-gray-400 mb-4">
|
<p class="text-gray-400 mb-4">
|
||||||
Utforska partier och deras ståndpunkter i olika frågor
|
Utforska partier och deras ståndpunkter i olika frågor
|
||||||
</p>
|
</p>
|
||||||
@@ -109,14 +227,30 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Placeholder Card 5 -->
|
<!-- Placeholder Card 5 -->
|
||||||
<div class="bg-white rounded-lg shadow-md border border-gray-200 overflow-hidden opacity-60">
|
<div
|
||||||
|
class="bg-white rounded-lg shadow-md border border-gray-200 overflow-hidden opacity-60"
|
||||||
|
>
|
||||||
<div class="p-6">
|
<div class="p-6">
|
||||||
<div class="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4">
|
<div
|
||||||
<svg class="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
class="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4"
|
||||||
<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
|
||||||
|
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>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="text-xl font-semibold text-gray-500 mb-2">Sök Allmänt</h3>
|
<h3 class="text-xl font-semibold text-gray-500 mb-2">
|
||||||
|
Sök Allmänt
|
||||||
|
</h3>
|
||||||
<p class="text-gray-400 mb-4">
|
<p class="text-gray-400 mb-4">
|
||||||
Sök i alla riksdagens dokument och voteringar
|
Sök i alla riksdagens dokument och voteringar
|
||||||
</p>
|
</p>
|
||||||
@@ -125,7 +259,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
361
resources/views/livewire/motion/search.blade.php
Normal file
361
resources/views/livewire/motion/search.blade.php
Normal file
@@ -0,0 +1,361 @@
|
|||||||
|
<div class="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
|
||||||
|
<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 class="font-medium text-gray-900">Sök Motioner</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<div class="text-center mb-8">
|
||||||
|
<h1 class="text-4xl font-bold text-gray-900 mb-4">Sök Motioner</h1>
|
||||||
|
<p class="text-lg text-gray-600">
|
||||||
|
Sök bland alla motioner som lämnats till riksdagen
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Search Form -->
|
||||||
|
<div
|
||||||
|
class="bg-white rounded-lg shadow-md border border-gray-200 p-6 mb-8"
|
||||||
|
>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||||
|
<!-- Query Search -->
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
for="query"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
|
Sökfras
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="query"
|
||||||
|
wire:model.live.debounce.500ms="query"
|
||||||
|
class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 text-black"
|
||||||
|
placeholder="Sök efter nyckelord..."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Party Select -->
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
for="party"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
|
Parti
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
id="party"
|
||||||
|
wire:model.live="party"
|
||||||
|
class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 text-black"
|
||||||
|
>
|
||||||
|
<option value="">Alla partier</option>
|
||||||
|
@foreach ($this->parties as $code => $name)
|
||||||
|
<option value="{{ $code }}">{{ $name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Date Interval -->
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
for="dateInterval"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
|
Riksdagsår
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
id="dateInterval"
|
||||||
|
wire:model.live="dateInterval"
|
||||||
|
class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 text-black"
|
||||||
|
>
|
||||||
|
<option value="">Alla år</option>
|
||||||
|
@foreach ($this->dateIntervals as $interval => $label)
|
||||||
|
<option value="{{ $interval }}">
|
||||||
|
{{ $label }}
|
||||||
|
</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Clear Filters Button -->
|
||||||
|
<div class="mt-4 flex justify-end">
|
||||||
|
<button
|
||||||
|
wire:click="clearFilters"
|
||||||
|
class="px-4 py-2 text-sm font-medium text-gray-700 bg-gray-100 border border-gray-300 rounded-md hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500"
|
||||||
|
>
|
||||||
|
Rensa filter
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Loading State -->
|
||||||
|
<div class="hidden" wire:loading.block>
|
||||||
|
<div class="flex justify-center items-center py-16">
|
||||||
|
<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 motioner...
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Results -->
|
||||||
|
@if (! $loading)
|
||||||
|
@if ($this->motions->isNotEmpty())
|
||||||
|
<!-- Results Header -->
|
||||||
|
<div
|
||||||
|
class="bg-white rounded-lg shadow-md border border-gray-200 p-4 mb-6"
|
||||||
|
>
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<h2 class="text-lg font-medium text-gray-900">
|
||||||
|
Hittade {{ number_format($this->totalResults) }}
|
||||||
|
motioner
|
||||||
|
</h2>
|
||||||
|
<div class="text-sm text-gray-500">
|
||||||
|
Sida {{ $this->getPage() }} av
|
||||||
|
{{ $paginatedMotions->lastPage() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Motion Cards -->
|
||||||
|
<div class="space-y-4 mb-8">
|
||||||
|
@foreach ($paginatedMotions as $motion)
|
||||||
|
<div
|
||||||
|
class="bg-white rounded-lg shadow-md border border-gray-200 p-6 hover:shadow-lg transition-shadow"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex flex-col lg:flex-row lg:items-start gap-4"
|
||||||
|
>
|
||||||
|
<div class="flex-1">
|
||||||
|
<div
|
||||||
|
class="flex items-start justify-between mb-3"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<h3
|
||||||
|
class="text-lg font-semibold text-gray-900 mb-1"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
wire:navigate
|
||||||
|
href="{{ route('motion.show', $motion->dok_id) }}"
|
||||||
|
class="hover:text-blue-600 transition-colors"
|
||||||
|
>
|
||||||
|
{{ $motion->titel }}
|
||||||
|
</a>
|
||||||
|
</h3>
|
||||||
|
@if (! empty($motion->undertitel))
|
||||||
|
<p
|
||||||
|
class="text-sm text-gray-600 mb-2"
|
||||||
|
>
|
||||||
|
{{ $motion->undertitel }}
|
||||||
|
</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
class="inline-flex px-3 py-1 text-xs font-semibold rounded-full {{ $motion->subtyp == 'Partimotion' ? 'bg-blue-100 text-blue-800' : 'bg-green-100 text-green-800' }}"
|
||||||
|
>
|
||||||
|
{{ $motion->subtyp }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="grid grid-cols-2 lg:grid-cols-4 gap-4 mb-4"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
class="text-xs font-medium text-gray-500 uppercase"
|
||||||
|
>
|
||||||
|
Beteckning
|
||||||
|
</span>
|
||||||
|
<p
|
||||||
|
class="text-sm font-medium text-gray-900"
|
||||||
|
>
|
||||||
|
{{ $motion->rm }}:{{ $motion->beteckning }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
class="text-xs font-medium text-gray-500 uppercase"
|
||||||
|
>
|
||||||
|
Datum
|
||||||
|
</span>
|
||||||
|
<p class="text-sm text-gray-900">
|
||||||
|
{{ \Carbon\Carbon::parse($motion->datum)->format('Y-m-d') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
class="text-xs font-medium text-gray-500 uppercase"
|
||||||
|
>
|
||||||
|
Status
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="inline-flex px-2 py-1 text-xs font-semibold rounded-full {{
|
||||||
|
$motion->status == 'Hänvisad'
|
||||||
|
? 'bg-yellow-100 text-yellow-800'
|
||||||
|
: ($motion->status == 'Avslutad'
|
||||||
|
? 'bg-green-100 text-green-800'
|
||||||
|
: 'bg-gray-100 text-gray-800')
|
||||||
|
}}"
|
||||||
|
>
|
||||||
|
{{ $motion->status }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
class="text-xs font-medium text-gray-500 uppercase"
|
||||||
|
>
|
||||||
|
Utskott
|
||||||
|
</span>
|
||||||
|
<p class="text-sm text-gray-900">
|
||||||
|
{{ $motion->organ ?: '-' }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (! empty($motion->summary))
|
||||||
|
<p
|
||||||
|
class="text-sm text-gray-700 line-clamp-3 mb-4"
|
||||||
|
>
|
||||||
|
{!! strip_tags($motion->summary, '<mark>') !!}
|
||||||
|
</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<div
|
||||||
|
class="flex-shrink-0 flex flex-row lg:flex-col gap-2"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
wire:navigate
|
||||||
|
href="{{ route('motion.show', $motion->dok_id) }}"
|
||||||
|
class="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 text-center"
|
||||||
|
>
|
||||||
|
Visa detaljer
|
||||||
|
</a>
|
||||||
|
@if (! empty($motion->dokument_url_html))
|
||||||
|
<a
|
||||||
|
href="https:{{ $motion->dokument_url_html }}"
|
||||||
|
target="_blank"
|
||||||
|
class="px-4 py-2 text-sm font-medium text-gray-700 bg-gray-100 rounded-md hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500 text-center"
|
||||||
|
>
|
||||||
|
Läs motion
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination -->
|
||||||
|
<div
|
||||||
|
class="bg-white rounded-lg shadow-md border border-gray-200 p-4"
|
||||||
|
>
|
||||||
|
@if ($paginatedMotions)
|
||||||
|
{{ $paginatedMotions->links() }}
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
@elseif (! empty($query) || ! empty($party) || ! empty($dateInterval))
|
||||||
|
<!-- No Results -->
|
||||||
|
<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="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
<h3 class="text-lg font-medium text-gray-900 mb-2">
|
||||||
|
Inga motioner hittades
|
||||||
|
</h3>
|
||||||
|
<p class="text-gray-600 mb-4">
|
||||||
|
Försök ändra dina sökkriterier.
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
wire:click="clearFilters"
|
||||||
|
class="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||||
|
>
|
||||||
|
Rensa filter
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<!-- Initial State -->
|
||||||
|
<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="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
<h3 class="text-lg font-medium text-gray-900 mb-2">
|
||||||
|
Börja din sökning
|
||||||
|
</h3>
|
||||||
|
<p class="text-gray-600">
|
||||||
|
Använd sökfälten ovan för att hitta motioner.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
486
resources/views/livewire/motion/show.blade.php
Normal file
486
resources/views/livewire/motion/show.blade.php
Normal file
@@ -0,0 +1,486 @@
|
|||||||
|
<div class="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
|
||||||
|
<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('motion.search') }}"
|
||||||
|
class="text-blue-600 hover:text-blue-700"
|
||||||
|
>
|
||||||
|
Sök Motioner
|
||||||
|
</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">
|
||||||
|
Motion
|
||||||
|
{{ $motion->rm ?? '' }}:{{ $motion->beteckning ?? $motionId }}
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
@if ($motion)
|
||||||
|
<!-- Motion Header -->
|
||||||
|
<div
|
||||||
|
class="bg-white rounded-lg shadow-md border border-gray-200 p-8 mb-8"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col lg:flex-row lg:items-start gap-6">
|
||||||
|
<div class="flex-1">
|
||||||
|
<div class="flex items-start justify-between mb-4">
|
||||||
|
<div>
|
||||||
|
<h1
|
||||||
|
class="text-3xl font-bold text-gray-900 mb-2"
|
||||||
|
>
|
||||||
|
{{ $motion->titel }}
|
||||||
|
</h1>
|
||||||
|
@if (! empty($motion->undertitel))
|
||||||
|
<p class="text-lg text-gray-600 mb-4">
|
||||||
|
{{ $motion->undertitel }}
|
||||||
|
</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
class="inline-flex px-3 py-1 text-sm font-semibold rounded-full {{ $motion->subtyp == 'Partimotion' ? 'bg-blue-100 text-blue-800' : 'bg-green-100 text-green-800' }}"
|
||||||
|
>
|
||||||
|
{{ $motion->subtyp }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Motion Details Grid -->
|
||||||
|
<div
|
||||||
|
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-6"
|
||||||
|
>
|
||||||
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
|
<div
|
||||||
|
class="text-sm font-medium text-gray-500 mb-1"
|
||||||
|
>
|
||||||
|
Beteckning
|
||||||
|
</div>
|
||||||
|
<div class="text-gray-900 font-semibold">
|
||||||
|
{{ $motion->rm }}:{{ $motion->beteckning }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
|
<div
|
||||||
|
class="text-sm font-medium text-gray-500 mb-1"
|
||||||
|
>
|
||||||
|
Datum
|
||||||
|
</div>
|
||||||
|
<div class="text-gray-900">
|
||||||
|
{{ \Carbon\Carbon::parse($motion->datum)->format('Y-m-d') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
|
<div
|
||||||
|
class="text-sm font-medium text-gray-500 mb-1"
|
||||||
|
>
|
||||||
|
Status
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
class="inline-flex px-2 py-1 text-xs font-semibold rounded-full {{
|
||||||
|
$motion->status == 'Hänvisad'
|
||||||
|
? 'bg-yellow-100 text-yellow-800'
|
||||||
|
: ($motion->status == 'Avslutad'
|
||||||
|
? 'bg-green-100 text-green-800'
|
||||||
|
: 'bg-gray-100 text-gray-800')
|
||||||
|
}}"
|
||||||
|
>
|
||||||
|
{{ $motion->status }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
|
<div
|
||||||
|
class="text-sm font-medium text-gray-500 mb-1"
|
||||||
|
>
|
||||||
|
Utskott
|
||||||
|
</div>
|
||||||
|
<div class="text-gray-900">
|
||||||
|
{{ $motion->organ ?: 'Ej tilldelat' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Action Buttons -->
|
||||||
|
<div class="flex flex-wrap gap-3">
|
||||||
|
@if (! empty($motion->dokument_url_html))
|
||||||
|
<a
|
||||||
|
href="https:{{ $motion->dokument_url_html }}"
|
||||||
|
target="_blank"
|
||||||
|
class="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-4 h-4 inline mr-1"
|
||||||
|
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>
|
||||||
|
Läs fullständig motion
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="{{ $this->riksdagenUrl }}"
|
||||||
|
target="_blank"
|
||||||
|
class="px-4 py-2 text-sm font-medium text-gray-700 bg-gray-100 rounded-md hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-4 h-4 inline mr-1"
|
||||||
|
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 på riksdag.se
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Motion Summary -->
|
||||||
|
@if (! empty($motion->summary))
|
||||||
|
<div
|
||||||
|
class="bg-white rounded-lg shadow-md border border-gray-200 p-6 mb-8"
|
||||||
|
>
|
||||||
|
<div class="flex items-center mb-4">
|
||||||
|
<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="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h2 class="text-xl font-bold text-gray-900">
|
||||||
|
Sammanfattning
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="prose max-w-none text-gray-700 whitespace-pre-line"
|
||||||
|
>
|
||||||
|
{!! strip_tags($motion->summary, '<mark>') !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<!-- Authors Section -->
|
||||||
|
@if ($this->authors->isNotEmpty())
|
||||||
|
<div
|
||||||
|
class="bg-white rounded-lg shadow-md border border-gray-200 p-6 mb-8"
|
||||||
|
>
|
||||||
|
<div class="flex items-center mb-4">
|
||||||
|
<div
|
||||||
|
class="w-10 h-10 bg-green-100 rounded-lg flex items-center justify-center mr-3"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-5 h-5 text-green-600"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197m13.5-9a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0z"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h2 class="text-xl font-bold text-gray-900">
|
||||||
|
Motionärer ({{ $this->authors->count() }})
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"
|
||||||
|
>
|
||||||
|
@foreach ($this->authors as $author)
|
||||||
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="font-semibold text-gray-900"
|
||||||
|
>
|
||||||
|
{{ $author->namn }}
|
||||||
|
</div>
|
||||||
|
<div class="text-sm text-gray-600">
|
||||||
|
{{ $author->partibet }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a
|
||||||
|
wire:navigate
|
||||||
|
href="{{ route('person.show', $author->intressent_id) }}"
|
||||||
|
class="text-blue-600 hover:text-blue-700 text-sm font-medium"
|
||||||
|
>
|
||||||
|
Visa profil
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<!-- File Attachments -->
|
||||||
|
@if ($this->attachments->isNotEmpty())
|
||||||
|
<div
|
||||||
|
class="bg-white rounded-lg shadow-md border border-gray-200 p-6 mb-8"
|
||||||
|
>
|
||||||
|
<div class="flex items-center mb-4">
|
||||||
|
<div
|
||||||
|
class="w-10 h-10 bg-purple-100 rounded-lg flex items-center justify-center mr-3"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-5 h-5 text-purple-600"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h2 class="text-xl font-bold text-gray-900">Bilagor</h2>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-3">
|
||||||
|
@foreach ($this->attachments as $file)
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between p-4 bg-gray-50 rounded-lg"
|
||||||
|
>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div class="flex-shrink-0">
|
||||||
|
@if ($file->typ == 'pdf')
|
||||||
|
<svg
|
||||||
|
class="w-8 h-8 text-red-600"
|
||||||
|
fill="currentColor"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm2 6a1 1 0 011-1h6a1 1 0 110 2H7a1 1 0 01-1-1zm1 3a1 1 0 100 2h6a1 1 0 100-2H7z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
@elseif ($file->typ == 'docx')
|
||||||
|
<svg
|
||||||
|
class="w-8 h-8 text-blue-600"
|
||||||
|
fill="currentColor"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm2 6a1 1 0 011-1h6a1 1 0 110 2H7a1 1 0 01-1-1zm1 3a1 1 0 100 2h6a1 1 0 100-2H7z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
@else
|
||||||
|
<svg
|
||||||
|
class="w-8 h-8 text-gray-600"
|
||||||
|
fill="currentColor"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm2 6a1 1 0 011-1h6a1 1 0 110 2H7a1 1 0 01-1-1zm1 3a1 1 0 100 2h6a1 1 0 100-2H7z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
<div class="ml-4">
|
||||||
|
<div
|
||||||
|
class="text-sm font-medium text-gray-900"
|
||||||
|
>
|
||||||
|
{{ $file->namn }}
|
||||||
|
</div>
|
||||||
|
<div class="text-sm text-gray-500">
|
||||||
|
{{ strtoupper($file->typ) }} •
|
||||||
|
{{ number_format($file->storlek / 1024, 1) }}
|
||||||
|
KB
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a
|
||||||
|
href="{{ $file->url }}"
|
||||||
|
target="_blank"
|
||||||
|
class="px-3 py-1 text-sm font-medium text-blue-600 bg-blue-50 rounded-md hover:bg-blue-100 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||||
|
>
|
||||||
|
Ladda ner
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<!-- Additional Information -->
|
||||||
|
<div
|
||||||
|
class="bg-white rounded-lg shadow-md border border-gray-200 p-6"
|
||||||
|
>
|
||||||
|
<div class="flex items-center mb-4">
|
||||||
|
<div
|
||||||
|
class="w-10 h-10 bg-gray-100 rounded-lg flex items-center justify-center mr-3"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-5 h-5 text-gray-600"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h2 class="text-xl font-bold text-gray-900">
|
||||||
|
Teknisk information
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
|
<div class="text-sm font-medium text-gray-500 mb-1">
|
||||||
|
Dokument-ID
|
||||||
|
</div>
|
||||||
|
<div class="text-gray-900 font-mono">
|
||||||
|
{{ $motion->dok_id }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
|
<div class="text-sm font-medium text-gray-500 mb-1">
|
||||||
|
Publicerad
|
||||||
|
</div>
|
||||||
|
<div class="text-gray-900">
|
||||||
|
{{ \Carbon\Carbon::parse($motion->publicerad)->format('Y-m-d') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
|
<div class="text-sm font-medium text-gray-500 mb-1">
|
||||||
|
Systemdatum
|
||||||
|
</div>
|
||||||
|
<div class="text-gray-900">
|
||||||
|
{{ \Carbon\Carbon::parse($motion->systemdatum)->format('Y-m-d H:i') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
|
<div class="text-sm font-medium text-gray-500 mb-1">
|
||||||
|
Källa
|
||||||
|
</div>
|
||||||
|
<div class="text-gray-900">{{ $motion->kalla }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<!-- Motion Not Found -->
|
||||||
|
<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">
|
||||||
|
Motion inte hittad
|
||||||
|
</h3>
|
||||||
|
<p class="text-gray-600 mb-4">
|
||||||
|
Motionen med ID {{ $motionId }} kunde inte hittas.
|
||||||
|
</p>
|
||||||
|
<a
|
||||||
|
wire:navigate
|
||||||
|
href="{{ route('motion.search') }}"
|
||||||
|
class="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||||
|
>
|
||||||
|
Tillbaka till sökning
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -88,14 +88,15 @@
|
|||||||
@foreach ($persons as $person)
|
@foreach ($persons as $person)
|
||||||
<div
|
<div
|
||||||
class="bg-gray-50 rounded-lg p-4 hover:bg-gray-100 transition-colors border border-gray-200">
|
class="bg-gray-50 rounded-lg p-4 hover:bg-gray-100 transition-colors border border-gray-200">
|
||||||
|
<a wire:navigate href="{{ route('person.show', $person->intressent_id) }}">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<img src="{{ $person->bild_url_80 ?? '' }}" alt="{{ $person->tilltalsnamn }}"
|
<img src="{{ $person->bild_url_80 ?? '' }}" alt="{{ $person->tilltalsnamn }}"
|
||||||
class="w-16 h-16 rounded-lg object-cover mr-4 border border-gray-300">
|
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) }}"
|
<span class="text-xl font-bold text-black transition-colors">
|
||||||
class="text-xl font-bold text-blue-600 hover:text-blue-700 transition-colors">
|
{{ $person->tilltalsnamn }} {{ $person->efternamn }}
|
||||||
{{ $person->tilltalsnamn }} {{ $person->efternamn }} ({{ $person->parti }})
|
({{ $person->parti }})
|
||||||
</a>
|
</span>
|
||||||
<div class="text-gray-600 mt-1 flex items-center gap-2">
|
<div class="text-gray-600 mt-1 flex items-center gap-2">
|
||||||
<img src="{{ App\Enums\Parties::from($person->parti)->logo() }}"
|
<img src="{{ App\Enums\Parties::from($person->parti)->logo() }}"
|
||||||
width="32">
|
width="32">
|
||||||
@@ -109,22 +110,24 @@
|
|||||||
d="M9 5l7 7-7 7"></path>
|
d="M9 5l7 7-7 7"></path>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
@elseif ($results && (!isset($results->personlista->person) || empty($results->personlista->person)))
|
@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="bg-yellow-50 border border-yellow-200 rounded-lg p-6 max-w-4xl mx-auto">
|
||||||
<div class="flex items-center">
|
<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">
|
<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"
|
<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>
|
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||||
</svg>
|
</svg>
|
||||||
<span class="text-yellow-800 font-medium">Inga ledamöter hittades med de angivna sökkriterier.</span>
|
<span class="text-yellow-800 font-medium">Inga ledamöter hittades med de angivna
|
||||||
|
sökkriterier.</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,306 +2,330 @@
|
|||||||
<div class="container mx-auto py-12 px-4">
|
<div class="container mx-auto py-12 px-4">
|
||||||
<!-- Breadcrumb Navigation -->
|
<!-- Breadcrumb Navigation -->
|
||||||
<nav class="mb-8" aria-label="Breadcrumb">
|
<nav class="mb-8" aria-label="Breadcrumb">
|
||||||
<div class="bg-white rounded-lg shadow-sm border border-gray-200 px-4 py-3">
|
<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">
|
<ol class="flex items-center space-x-2 text-sm text-gray-600">
|
||||||
<li>
|
<li>
|
||||||
<a wire:navigate href="{{ route('home') }}" class="text-blue-600 hover:text-blue-700 flex items-center">
|
<a
|
||||||
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
wire:navigate
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
href="{{ route('home') }}"
|
||||||
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">
|
class="text-blue-600 hover:text-blue-700 flex items-center"
|
||||||
</path>
|
>
|
||||||
|
<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>
|
</svg>
|
||||||
Hem
|
Hem
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<svg class="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
|
<svg
|
||||||
<path fill-rule="evenodd"
|
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"
|
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>
|
clip-rule="evenodd"
|
||||||
|
></path>
|
||||||
</svg>
|
</svg>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a wire:navigate href="{{ route('person.search') }}" class="text-blue-600 hover:text-blue-700">Sök
|
<a
|
||||||
Ledamöter</a>
|
wire:navigate
|
||||||
|
href="{{ route('person.search') }}"
|
||||||
|
class="text-blue-600 hover:text-blue-700"
|
||||||
|
>
|
||||||
|
Sök Ledamöter
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<svg class="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
|
<svg
|
||||||
<path fill-rule="evenodd"
|
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"
|
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>
|
clip-rule="evenodd"
|
||||||
|
></path>
|
||||||
</svg>
|
</svg>
|
||||||
</li>
|
</li>
|
||||||
<li class="font-medium text-gray-900">
|
<li class="font-medium text-gray-900">
|
||||||
{{ $person->tilltalsnamn ?? 'Laddar...' }} {{ $person->efternamn ?? '' }}
|
{{ $person->tilltalsnamn ?? 'Laddar...' }}
|
||||||
|
{{ $person->efternamn ?? '' }}
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@if ($person)
|
@if ($person)
|
||||||
<!-- Main Profile Section -->
|
<!-- Main Profile Section -->
|
||||||
<div class="bg-white rounded-lg shadow-md border border-gray-200 p-8 mb-8">
|
<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 class="md:w-48">
|
<div class="md:w-48">
|
||||||
<img src="{{ $person->bild_url_max ?? '' }}" alt="{{ $person->tilltalsnamn }}"
|
<img
|
||||||
class="w-full h-64 md:w-48 object-cover rounded-lg shadow-lg border border-gray-200">
|
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"
|
||||||
|
/>
|
||||||
|
<span class="text-xs text-gray-500 mt-2 block">
|
||||||
|
Foto: Sveriges Riksdag
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<h1 class="text-4xl font-bold text-gray-900 mb-2">{{ $person->tilltalsnamn }}
|
<h1 class="text-4xl font-bold text-gray-900 mb-2">
|
||||||
{{ $person->efternamn }} ({{ $person->parti }})</h1>
|
{{ $person->tilltalsnamn }}
|
||||||
|
{{ $person->efternamn }}
|
||||||
|
({{ $person->parti }})
|
||||||
|
</h1>
|
||||||
<div class="flex flex-wrap items-center gap-4 mb-4">
|
<div class="flex flex-wrap items-center gap-4 mb-4">
|
||||||
<span
|
<span
|
||||||
class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-blue-100 text-blue-800 grap-2">
|
class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-blue-100 text-blue-800 grap-2"
|
||||||
|
>
|
||||||
{{ App\Enums\Parties::from($person->parti)->label() }}
|
{{ App\Enums\Parties::from($person->parti)->label() }}
|
||||||
<img src="{{ App\Enums\Parties::from($person->parti)->logo() }}" width="32">
|
<img
|
||||||
|
src="{{ App\Enums\Parties::from($person->parti)->logo() }}"
|
||||||
|
width="32"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span class="text-gray-600">
|
||||||
|
{{ $person->valkrets }} valkrets
|
||||||
</span>
|
</span>
|
||||||
<span class="text-gray-600">{{ $person->valkrets }} valkrets</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
|
<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="bg-gray-50 rounded-lg p-4">
|
||||||
<div class="text-sm font-medium text-gray-500 mb-1">Född</div>
|
<div
|
||||||
<div class="text-gray-900">{{ $person->fodd_ar }}</div>
|
class="text-sm font-medium text-gray-500 mb-1"
|
||||||
|
>
|
||||||
|
Född
|
||||||
|
</div>
|
||||||
|
<div class="text-gray-900">
|
||||||
|
{{ $person->fodd_ar }}
|
||||||
|
({{ Carbon\Carbon::parse($person->fodd_ar)->age }}
|
||||||
|
år)
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-gray-50 rounded-lg p-4">
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
<div class="text-sm font-medium text-gray-500 mb-1">Kön</div>
|
<div
|
||||||
<div class="text-gray-900">{{ ucfirst($person->kon) }}</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>
|
||||||
<div class="bg-gray-50 rounded-lg p-4">
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
<div class="text-sm font-medium text-gray-500 mb-1">Status</div>
|
<div
|
||||||
<div class="text-gray-900">{{ $person->status }}</div>
|
class="text-sm font-medium text-gray-500 mb-1"
|
||||||
|
>
|
||||||
|
Status
|
||||||
|
</div>
|
||||||
|
<div class="text-gray-900">
|
||||||
|
{{ $person->status }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-gray-50 rounded-lg p-4">
|
<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-sm font-medium text-gray-500 mb-1"
|
||||||
|
>
|
||||||
|
E-post
|
||||||
|
</div>
|
||||||
<div class="text-gray-900 text-sm">
|
<div class="text-gray-900 text-sm">
|
||||||
{{ str_replace('[på]', '@', collect($person->personuppgift->uppgift ?? [])->firstWhere('kod', 'Officiell e-postadress')->uppgift[0] ?? '-') }}
|
{{ str_replace('[på]', '@', collect($person->personuppgift->uppgift ?? [])->firstWhere('kod', 'Officiell e-postadress')->uppgift[0] ?? '-') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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 på riksdagen.se
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Assignments Section -->
|
@if (! empty($votesByYear))
|
||||||
<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>
|
|
||||||
|
|
||||||
<!-- Uppdrag tabs -->
|
|
||||||
<div class="border-b border-gray-200 mb-6">
|
|
||||||
<nav class="-mb-px flex space-x-8">
|
|
||||||
<button 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' }}">
|
|
||||||
<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) }})
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
<button 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' }}">
|
|
||||||
<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) }})
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Current assignments -->
|
|
||||||
@if ($selectedUppdragTab == 'current' && !empty($currentUppdrag))
|
|
||||||
<div class="space-y-3">
|
|
||||||
@foreach ($currentUppdrag as $uppdrag)
|
|
||||||
<div class="bg-green-50 border border-green-200 rounded-lg p-4">
|
|
||||||
<div class="flex justify-between items-start">
|
|
||||||
<div>
|
|
||||||
<h4 class="font-semibold text-green-800">{{ $uppdrag->roll_kod }}</h4>
|
|
||||||
{{-- @if (!empty($uppdrag->uppgift[0]) && is_array($uppdrag->uppgift))
|
|
||||||
<p class="text-sm text-green-700 mt-1">{{ implode(', ', $uppdrag->uppgift) }}</p>
|
|
||||||
@endif --}}
|
|
||||||
<p class="text-sm text-green-600 mt-2">
|
|
||||||
<span class="font-medium">Typ:</span> {{ ucfirst($uppdrag->typ) }}
|
|
||||||
@if (isset($uppdrag->status) && $uppdrag->status)
|
|
||||||
| <span class="font-medium">Status:</span> {{ $uppdrag->status }}
|
|
||||||
@endif
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="text-right text-sm text-green-600">
|
|
||||||
<div>Från: {{ Carbon\Carbon::parse($uppdrag->from)->format('Y-m-d') }}</div>
|
|
||||||
@if (!empty($uppdrag->tom))
|
|
||||||
<div>Till: {{ Carbon\Carbon::parse($uppdrag->tom)->format('Y-m-d') }}</div>
|
|
||||||
@else
|
|
||||||
<div class="font-semibold text-green-700">Pågående</div>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endforeach
|
|
||||||
</div>
|
|
||||||
@elseif($selectedUppdragTab == 'current' && empty($currentUppdrag))
|
|
||||||
<p class="text-gray-500 italic">Inga pågående uppdrag.</p>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
<!-- Previous assignments -->
|
|
||||||
@if ($selectedUppdragTab == 'previous' && !empty($previousUppdrag))
|
|
||||||
<div class="space-y-3">
|
|
||||||
@foreach ($previousUppdrag as $uppdrag)
|
|
||||||
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4">
|
|
||||||
<div class="flex justify-between items-start">
|
|
||||||
<div>
|
|
||||||
<h4 class="font-semibold text-gray-800">{{ $uppdrag->roll_kod }}</h4>
|
|
||||||
{{-- @if (!empty($uppdrag->uppgift[0]) && is_array($uppdrag->uppgift))
|
|
||||||
<p class="text-sm text-gray-700 mt-1">{{ implode(', ', $uppdrag->uppgift) }}</p>
|
|
||||||
@endif --}}
|
|
||||||
<p class="text-sm text-gray-600 mt-2">
|
|
||||||
<span class="font-medium">Typ:</span> {{ ucfirst($uppdrag->typ) }}
|
|
||||||
@if (isset($uppdrag->status) && $uppdrag->status)
|
|
||||||
| <span class="font-medium">Status:</span> {{ $uppdrag->status }}
|
|
||||||
@endif
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<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 class="text-xs text-gray-500 mt-1">
|
|
||||||
{{ Carbon\Carbon::parse($uppdrag->from)->diffForHumans(Carbon\Carbon::parse($uppdrag->tom), true) }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endforeach
|
|
||||||
</div>
|
|
||||||
@elseif($selectedUppdragTab == 'previous' && empty($previousUppdrag))
|
|
||||||
<p class="text-gray-500 italic">Inga tidigare uppdrag registrerade.</p>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
@if (!empty($votesByYear))
|
|
||||||
<!-- Voting Section -->
|
<!-- Voting Section -->
|
||||||
<div class="bg-white rounded-lg shadow-md border border-gray-200 p-6 mb-8">
|
<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="flex items-center mb-6">
|
||||||
<div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center mr-3">
|
<div
|
||||||
<svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor"
|
class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center mr-3"
|
||||||
viewBox="0 0 24 24">
|
>
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
<svg
|
||||||
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">
|
class="w-5 h-5 text-blue-600"
|
||||||
</path>
|
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 2m-6 9l2 2 4-4"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="text-2xl font-bold text-gray-900">Voteringar</h2>
|
<h2 class="text-2xl font-bold text-gray-900">
|
||||||
|
Voteringar
|
||||||
|
</h2>
|
||||||
</div>
|
</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 wire:click="selectYear('{{ $year }}')"
|
<button
|
||||||
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' }}">
|
wire:click="selectVotesYear('{{ $year }}')"
|
||||||
|
class="cursor-pointer py-2 px-1 border-b-2 font-medium text-sm {{ $votesSelectedYear == $year ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300' }}"
|
||||||
|
>
|
||||||
{{ $year }}
|
{{ $year }}
|
||||||
</button>
|
</button>
|
||||||
@endforeach
|
@endforeach
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
@if ($votesSelectedYear && isset($votesByYear[$votesSelectedYear]))
|
||||||
@if ($selectedYear && isset($votesByYear[$selectedYear]))
|
<!-- Voting Statistics -->
|
||||||
<!-- Voting Statistics Chart -->
|
<div
|
||||||
<div class="mb-8 bg-gray-200 p-6 rounded-lg shadow border">
|
class="mb-8 bg-gray-200 p-6 rounded-lg shadow border"
|
||||||
@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 style="height: 23rem;">
|
<div style="height: 23rem">
|
||||||
<livewire:livewire-pie-chart :pie-chart-model="$this->pieChartModel"
|
<livewire:livewire-pie-chart
|
||||||
key="{{ 'pie-chart-' . $selectedYear }}" />
|
:pie-chart-model="$this->pieChartModel"
|
||||||
|
key="{{ 'pie-chart-' . $votesSelectedYear }}"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="lg:w-1/2 my-auto">
|
<div class="lg:w-1/2 my-auto">
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
@php($totalVotes = array_sum($this->votingStatistics))
|
@php($totalVotes = array_sum($this->votingStatistics))
|
||||||
|
|
||||||
@foreach ($this->votingStatistics as $voteType => $count)
|
@foreach ($this->votingStatistics as $voteType => $count)
|
||||||
<div class="flex justify-between items-center p-3 bg-gray-50 rounded">
|
<div
|
||||||
<span class="text-black font-medium">{{ $voteType }}</span>
|
class="flex justify-between items-center p-3 bg-gray-50 rounded"
|
||||||
<span class="text-black text-lg font-bold">{{ $count }}
|
>
|
||||||
({{ round(($count / $totalVotes) * 100, 2) }}%)</span>
|
<span
|
||||||
|
class="text-black font-medium"
|
||||||
|
>
|
||||||
|
{{ $voteType }}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="text-black text-lg font-bold"
|
||||||
|
>
|
||||||
|
{{ $count }}
|
||||||
|
({{ round(($count / $totalVotes) * 100, 2) }}%)
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="flex justify-between items-center p-3 bg-blue-50 rounded border-t-2 border-blue-500">
|
class="flex justify-between items-center p-3 bg-blue-50 rounded border-t-2 border-blue-500"
|
||||||
<span class="text-black font-bold">Totalt antal voteringar</span>
|
>
|
||||||
<span
|
<span
|
||||||
class="text-black text-lg font-bold">{{ array_sum($this->votingStatistics) }}</span>
|
class="text-black font-bold"
|
||||||
|
>
|
||||||
|
Totalt antal voteringar
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="text-black text-lg font-bold"
|
||||||
|
>
|
||||||
|
{{ $totalVotes }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
<p class="text-gray-500">Ingen voteringsstatistik 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
|
|
||||||
|
|
||||||
<!-- Votes table -->
|
<!-- Votes table -->
|
||||||
@if ($selectedYear && isset($votesByYear[$selectedYear]))
|
<div
|
||||||
<div class="overflow-x-auto" style="overflow-y: auto; display: block; max-height: 400px;">
|
class="overflow-x-auto overflow-y-auto max-h-[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
|
<th
|
||||||
class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase"
|
||||||
Datum</th>
|
>
|
||||||
|
Datum
|
||||||
|
</th>
|
||||||
<th
|
<th
|
||||||
class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase"
|
||||||
Beteckning</th>
|
>
|
||||||
|
Beteckning
|
||||||
|
</th>
|
||||||
<th
|
<th
|
||||||
class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase"
|
||||||
Punkt</th>
|
>
|
||||||
|
Punkt
|
||||||
|
</th>
|
||||||
<th
|
<th
|
||||||
class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase"
|
||||||
Röst</th>
|
>
|
||||||
|
Röst
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody class="divide-y divide-gray-100">
|
<tbody class="divide-y divide-gray-100">
|
||||||
@foreach ($votesByYear[$selectedYear] as $vote)
|
@foreach ($votesByYear[$votesSelectedYear] as $vote)
|
||||||
<tr class="bg-gray-200">
|
<tr class="bg-gray-200">
|
||||||
<td class="px-4 py-2 text-sm text-gray-900">
|
<td
|
||||||
{{ Carbon\Carbon::parse($vote->systemdatum)->format('Y-m-d') }}
|
class="px-4 py-2 text-sm text-gray-900"
|
||||||
|
>
|
||||||
|
{{ \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 }}"
|
<a
|
||||||
class="text-blue-600 hover:underline" target="_blank">
|
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
|
<span
|
||||||
class="inline-flex px-2 py-1 text-xs font-semibold rounded-full
|
class="inline-flex px-2 py-1 text-xs font-semibold rounded-full {{
|
||||||
{{ $vote->rost === 'Ja'
|
$vote->rost === 'Ja'
|
||||||
? 'bg-green-100 text-green-800'
|
? 'bg-green-100 text-green-800'
|
||||||
: ($vote->rost === 'Nej'
|
: ($vote->rost === 'Nej'
|
||||||
? 'bg-red-100 text-red-800'
|
? 'bg-red-100 text-red-800'
|
||||||
: 'bg-gray-100 text-gray-800') }}">
|
: 'bg-gray-100 text-gray-800')
|
||||||
|
}}"
|
||||||
|
>
|
||||||
{{ $vote->rost }}
|
{{ $vote->rost }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
@@ -310,18 +334,400 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
@else
|
||||||
|
<p class="text-gray-500">
|
||||||
|
Inga voteringar tillgängliga för detta år.
|
||||||
|
</p>
|
||||||
@endif
|
@endif
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<!-- Motions 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-green-100 rounded-lg flex items-center justify-center mr-3"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-5 h-5 text-green-600"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h2 class="text-2xl font-bold text-gray-900">Motioner</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Year tabs for motions -->
|
||||||
|
@if (! empty($motionsByYear))
|
||||||
|
<div class="border-b border-gray-200 mb-4">
|
||||||
|
<nav class="-mb-px flex space-x-8">
|
||||||
|
@foreach (array_keys($motionsByYear) as $year)
|
||||||
|
<button
|
||||||
|
wire:click="selectMotionsYear('{{ $year }}')"
|
||||||
|
class="cursor-pointer py-2 px-1 border-b-2 font-medium text-sm {{ $motionsSelectedYear == $year ? 'border-green-500 text-green-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300' }}"
|
||||||
|
>
|
||||||
|
{{ $year }}
|
||||||
|
({{ count($motionsByYear[$year]) }})
|
||||||
|
</button>
|
||||||
|
@endforeach
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if ($motionsSelectedYear && isset($motionsByYear[$motionsSelectedYear]))
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="min-w-full divide-y divide-gray-200">
|
||||||
|
<thead class="bg-gray-50">
|
||||||
|
<tr>
|
||||||
|
<th
|
||||||
|
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||||
|
>
|
||||||
|
Beteckning
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||||
|
>
|
||||||
|
Titel
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||||
|
>
|
||||||
|
Typ
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||||
|
>
|
||||||
|
Datum
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||||
|
>
|
||||||
|
Status
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||||
|
>
|
||||||
|
Åtgärder
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody
|
||||||
|
class="bg-white divide-y divide-gray-200"
|
||||||
|
>
|
||||||
|
@foreach ($motionsByYear[$motionsSelectedYear] as $motion)
|
||||||
|
<tr class="hover:bg-gray-50">
|
||||||
|
<td
|
||||||
|
class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900"
|
||||||
|
>
|
||||||
|
{{ $motionsSelectedYear }}:{{ $motion->beteckning }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="px-6 py-4 text-sm text-gray-900"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="max-w-xs truncate"
|
||||||
|
title="{{ $motion->titel }}"
|
||||||
|
>
|
||||||
|
{{ $motion->titel }}
|
||||||
|
</div>
|
||||||
|
@if (! empty($motion->undertitel))
|
||||||
|
<div
|
||||||
|
class="text-xs text-gray-500 mt-1"
|
||||||
|
>
|
||||||
|
{{ $motion->undertitel }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="inline-flex px-2 py-1 text-xs font-semibold rounded-full {{ $motion->subtyp == 'Partimotion' ? 'bg-blue-100 text-blue-800' : 'bg-gray-100 text-gray-800' }}"
|
||||||
|
>
|
||||||
|
{{ $motion->subtyp }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"
|
||||||
|
>
|
||||||
|
{{ \Carbon\Carbon::parse($motion->datum)->format('Y-m-d') }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="inline-flex px-2 py-1 text-xs font-semibold rounded-full {{
|
||||||
|
$motion->status == 'LagdTillHandlingarna'
|
||||||
|
? 'bg-yellow-100 text-yellow-800'
|
||||||
|
: ($motion->status == 'Avslutad'
|
||||||
|
? 'bg-green-100 text-green-800'
|
||||||
|
: 'bg-gray-100 text-gray-800')
|
||||||
|
}}"
|
||||||
|
>
|
||||||
|
{{ $motion->status }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="px-6 py-4 whitespace-nowrap text-sm font-medium"
|
||||||
|
>
|
||||||
|
@if (! empty($motion->dokument_url_html))
|
||||||
|
<a
|
||||||
|
href="https:{{ $motion->dokument_url_html }}"
|
||||||
|
target="_blank"
|
||||||
|
class="text-green-600 hover:text-green-900 mr-4"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-4 h-4 inline"
|
||||||
|
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>
|
||||||
|
Läs
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<p class="text-gray-500">
|
||||||
|
Inga motioner tillgängliga för detta år.
|
||||||
|
</p>
|
||||||
|
@endif
|
||||||
|
@else
|
||||||
|
<p class="text-gray-500">
|
||||||
|
Inga motioner tillgängliga för denna person.
|
||||||
|
</p>
|
||||||
|
@endif
|
||||||
|
</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>
|
||||||
|
|
||||||
|
<!-- Uppdrag tabs -->
|
||||||
|
<div class="border-b border-gray-200 mb-6">
|
||||||
|
<nav class="-mb-px flex space-x-8">
|
||||||
|
<button
|
||||||
|
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' }}"
|
||||||
|
>
|
||||||
|
<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) }})
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
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' }}"
|
||||||
|
>
|
||||||
|
<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) }})
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Current assignments -->
|
||||||
|
@if ($selectedUppdragTab == 'current' && ! empty($currentUppdrag))
|
||||||
|
<div class="space-y-3">
|
||||||
|
@foreach ($currentUppdrag as $uppdrag)
|
||||||
|
<div
|
||||||
|
class="bg-green-50 border border-green-200 rounded-lg p-4"
|
||||||
|
>
|
||||||
|
<div class="flex justify-between items-start">
|
||||||
|
<div>
|
||||||
|
<h4
|
||||||
|
class="font-semibold text-green-800"
|
||||||
|
>
|
||||||
|
{{ $uppdrag->roll_kod }}
|
||||||
|
</h4>
|
||||||
|
{{--
|
||||||
|
@if (!empty($uppdrag->uppgift[0]) && is_array($uppdrag->uppgift))
|
||||||
|
<p class="text-sm text-green-700 mt-1">{{ implode(', ', $uppdrag->uppgift) }}</p>
|
||||||
|
@endif
|
||||||
|
--}}
|
||||||
|
<p class="text-sm text-green-600 mt-2">
|
||||||
|
<span class="font-medium">
|
||||||
|
Typ:
|
||||||
|
</span>
|
||||||
|
{{ ucfirst($uppdrag->typ) }}
|
||||||
|
@if (isset($uppdrag->status) && $uppdrag->status)
|
||||||
|
|
|
||||||
|
<span class="font-medium">
|
||||||
|
Status:
|
||||||
|
</span>
|
||||||
|
{{ $uppdrag->status }}
|
||||||
|
@endif
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="text-right text-sm text-green-600"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
Från:
|
||||||
|
{{ Carbon\Carbon::parse($uppdrag->from)->format('Y-m-d') }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (! empty($uppdrag->tom))
|
||||||
|
<div>
|
||||||
|
Till:
|
||||||
|
{{ Carbon\Carbon::parse($uppdrag->tom)->format('Y-m-d') }}
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<div
|
||||||
|
class="font-semibold text-green-700"
|
||||||
|
>
|
||||||
|
Pågående
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
@elseif ($selectedUppdragTab == 'current' && empty($currentUppdrag))
|
||||||
|
<p class="text-gray-500 italic">Inga pågående uppdrag.</p>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<!-- Previous assignments -->
|
||||||
|
@if ($selectedUppdragTab == 'previous' && ! empty($previousUppdrag))
|
||||||
|
<div class="space-y-3">
|
||||||
|
@foreach ($previousUppdrag as $uppdrag)
|
||||||
|
<div
|
||||||
|
class="bg-gray-50 border border-gray-200 rounded-lg p-4"
|
||||||
|
>
|
||||||
|
<div class="flex justify-between items-start">
|
||||||
|
<div>
|
||||||
|
<h4 class="font-semibold text-gray-800">
|
||||||
|
{{ $uppdrag->roll_kod }}
|
||||||
|
</h4>
|
||||||
|
{{--
|
||||||
|
@if (!empty($uppdrag->uppgift[0]) && is_array($uppdrag->uppgift))
|
||||||
|
<p class="text-sm text-gray-700 mt-1">{{ implode(', ', $uppdrag->uppgift) }}</p>
|
||||||
|
@endif
|
||||||
|
--}}
|
||||||
|
<p class="text-sm text-gray-600 mt-2">
|
||||||
|
<span class="font-medium">
|
||||||
|
Typ:
|
||||||
|
</span>
|
||||||
|
{{ ucfirst($uppdrag->typ) }}
|
||||||
|
@if (isset($uppdrag->status) && $uppdrag->status)
|
||||||
|
|
|
||||||
|
<span class="font-medium">
|
||||||
|
Status:
|
||||||
|
</span>
|
||||||
|
{{ $uppdrag->status }}
|
||||||
|
@endif
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<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 class="text-xs text-gray-500 mt-1">
|
||||||
|
{{ Carbon\Carbon::parse($uppdrag->from)->diffForHumans(Carbon\Carbon::parse($uppdrag->tom), true) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
@elseif ($selectedUppdragTab == 'previous' && empty($previousUppdrag))
|
||||||
|
<p class="text-gray-500 italic">
|
||||||
|
Inga tidigare uppdrag registrerade.
|
||||||
|
</p>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Biography Section -->
|
<!-- Biography Section -->
|
||||||
<div class="bg-white rounded-lg shadow-md border border-gray-200 p-6 mb-8">
|
<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="flex items-center mb-6">
|
||||||
<div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center mr-3">
|
<div
|
||||||
<svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center mr-3"
|
||||||
<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">
|
<svg
|
||||||
</path>
|
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>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="text-2xl font-bold text-gray-900">Biografi</h2>
|
<h2 class="text-2xl font-bold text-gray-900">Biografi</h2>
|
||||||
@@ -329,22 +735,40 @@
|
|||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
@foreach (collect($person->personuppgift->uppgift ?? [])->where('typ', 'biografi') as $bio)
|
@foreach (collect($person->personuppgift->uppgift ?? [])->where('typ', 'biografi') as $bio)
|
||||||
<div class="bg-gray-50 rounded-lg p-4">
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
<div class="font-semibold text-gray-900 mb-2">{{ $bio->kod }}</div>
|
<div class="font-semibold text-gray-900 mb-2">
|
||||||
|
{{ $bio->kod }}
|
||||||
|
</div>
|
||||||
<div class="text-gray-700">
|
<div class="text-gray-700">
|
||||||
{{ is_array($bio->uppgift) ? implode(', ', $bio->uppgift) : $bio->uppgift }}</div>
|
{{ is_array($bio->uppgift) ? implode(', ', $bio->uppgift) : $bio->uppgift }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
<div class="bg-white rounded-lg shadow-md border border-gray-200 p-8 text-center">
|
<div
|
||||||
<svg class="w-16 h-16 text-gray-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
class="bg-white rounded-lg shadow-md border border-gray-200 p-8 text-center"
|
||||||
<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
|
||||||
|
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>
|
</svg>
|
||||||
<h3 class="text-lg font-medium text-gray-900 mb-2">Person inte hittad</h3>
|
<h3 class="text-lg font-medium text-gray-900 mb-2">
|
||||||
<p class="text-gray-600">Personen kunde inte hittas i databasen.</p>
|
Person inte hittad
|
||||||
|
</h3>
|
||||||
|
<p class="text-gray-600">
|
||||||
|
Personen kunde inte hittas i databasen.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Livewire\HomePage;
|
||||||
|
use App\Livewire\Motion\Search as MotionSearch;
|
||||||
|
use App\Livewire\Motion\Show as MotionShow;
|
||||||
|
use App\Livewire\Person\Search as PersonSearch;
|
||||||
|
use App\Livewire\Person\Show as PersonShow;
|
||||||
use App\Livewire\Settings\Appearance;
|
use App\Livewire\Settings\Appearance;
|
||||||
use App\Livewire\Settings\Password;
|
use App\Livewire\Settings\Password;
|
||||||
use App\Livewire\Settings\Profile;
|
use App\Livewire\Settings\Profile;
|
||||||
@@ -7,15 +12,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\Show as PersonShow;
|
|
||||||
|
|
||||||
Route::get('/', HomePage::class)->name('home');
|
Route::get('/', HomePage::class)->name('home');
|
||||||
|
|
||||||
Route::get('/ledamot', PersonSearch::class)->name('person.search');
|
Route::get('/ledamot', PersonSearch::class)->name('person.search');
|
||||||
Route::get('/ledamot/{personId}', PersonShow::class)->name('person.show');
|
Route::get('/ledamot/{personId}', PersonShow::class)->name('person.show');
|
||||||
|
|
||||||
|
Route::get('/motion', MotionSearch::class)->name('motion.search');
|
||||||
|
Route::get('/motion/{motionId}', MotionShow::class)->name('motion.show');
|
||||||
|
|
||||||
Route::view('dashboard', 'dashboard')
|
Route::view('dashboard', 'dashboard')
|
||||||
->middleware(['auth', 'verified'])
|
->middleware(['auth', 'verified'])
|
||||||
->name('dashboard');
|
->name('dashboard');
|
||||||
|
|||||||
Reference in New Issue
Block a user