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;
|
||||
|
||||
use Livewire\Component;
|
||||
use App\Services\RiksdagenService;
|
||||
use App\Enums\Parties;
|
||||
use App\Services\RiksdagenService;
|
||||
use Livewire\Component;
|
||||
|
||||
class Search extends Component
|
||||
{
|
||||
public $firstName = '';
|
||||
|
||||
public $lastName = '';
|
||||
|
||||
public $party = '';
|
||||
|
||||
public $results = [];
|
||||
|
||||
public $parties = [];
|
||||
|
||||
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()
|
||||
{
|
||||
$service = app(RiksdagenService::class);
|
||||
|
||||
$this->results = $service->searchPerson(
|
||||
firstName: $this->firstName,
|
||||
lastName: $this->lastName,
|
||||
party: $this->party
|
||||
party: $this->party,
|
||||
)->original;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
namespace App\Livewire\Person;
|
||||
|
||||
use Livewire\Component;
|
||||
use App\Services\RiksdagenService;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Asantibanez\LivewireCharts\Models\PieChartModel;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Lazy;
|
||||
use Livewire\Component;
|
||||
|
||||
#[Lazy()]
|
||||
class Show extends Component
|
||||
@@ -17,9 +18,15 @@ class Show extends Component
|
||||
|
||||
public $votes = [];
|
||||
|
||||
public $motions = [];
|
||||
|
||||
public $votesByYear = [];
|
||||
|
||||
public $selectedYear;
|
||||
public $motionsByYear = [];
|
||||
|
||||
public $votesSelectedYear;
|
||||
|
||||
public $motionsSelectedYear;
|
||||
|
||||
public $selectedUppdragTab = 'current';
|
||||
|
||||
@@ -27,47 +34,87 @@ class Show extends Component
|
||||
|
||||
public $previousUppdrag = [];
|
||||
|
||||
private RiksdagenService $service;
|
||||
|
||||
public function mount($personId)
|
||||
{
|
||||
$this->personId = $personId;
|
||||
$service = app(RiksdagenService::class);
|
||||
$result = $service->searchPerson(mp_id: $personId);
|
||||
$this->service = app(RiksdagenService::class);
|
||||
$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->getPersonVotes();
|
||||
$this->getPersonMotions();
|
||||
$this->groupUppdrag();
|
||||
}
|
||||
|
||||
#[Computed()]
|
||||
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()
|
||||
{
|
||||
$service = app(RiksdagenService::class);
|
||||
$result = $service->searchVotes(mp_id: $this->personId);
|
||||
$result = Cache::remember('person_votes_'.$this->personId, 24 * 60 * 60, function () {
|
||||
return $this->service->searchVotes(mp_id: $this->personId);
|
||||
});
|
||||
|
||||
$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) {
|
||||
$year = explode('/', $vote->rm)[0]; // Extract year from rm like "2025/26"
|
||||
if (!isset($this->votesByYear[$year])) {
|
||||
$this->votesByYear[$year] = [];
|
||||
$rm = $vote->rm;
|
||||
if (! isset($this->votesByYear[$rm])) {
|
||||
$this->votesByYear[$rm] = [];
|
||||
}
|
||||
$this->votesByYear[$year][] = $vote;
|
||||
$this->votesByYear[$rm][] = $vote;
|
||||
}
|
||||
|
||||
// Set default selected year to the most recent
|
||||
if (!empty($this->votesByYear)) {
|
||||
$this->selectedYear = max(array_keys($this->votesByYear));
|
||||
if (! empty($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)
|
||||
@@ -77,7 +124,7 @@ class Show extends Component
|
||||
|
||||
public function groupUppdrag()
|
||||
{
|
||||
if (!$this->person || !isset($this->person->personuppdrag->uppdrag)) {
|
||||
if (! $this->person || ! isset($this->person->personuppdrag->uppdrag)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -98,11 +145,11 @@ class Show extends Component
|
||||
}
|
||||
|
||||
// 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;
|
||||
});
|
||||
|
||||
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;
|
||||
});
|
||||
}
|
||||
@@ -110,16 +157,16 @@ class Show extends Component
|
||||
#[Computed()]
|
||||
public function votingStatistics()
|
||||
{
|
||||
if (!$this->selectedYear || !isset($this->votesByYear[$this->selectedYear])) {
|
||||
if (! $this->votesSelectedYear || ! isset($this->votesByYear[$this->votesSelectedYear])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$votes = $this->votesByYear[$this->selectedYear];
|
||||
$votes = $this->votesByYear[$this->votesSelectedYear];
|
||||
$statistics = [];
|
||||
|
||||
foreach ($votes as $vote) {
|
||||
$voteType = $vote->rost;
|
||||
if (!isset($statistics[$voteType])) {
|
||||
if (! isset($statistics[$voteType])) {
|
||||
$statistics[$voteType] = 0;
|
||||
}
|
||||
$statistics[$voteType]++;
|
||||
@@ -133,8 +180,8 @@ class Show extends Component
|
||||
{
|
||||
$statistics = $this->votingStatistics;
|
||||
|
||||
$pieChart = (new PieChartModel())
|
||||
->setTitle('Voteringsstatistik för ' . $this->selectedYear)
|
||||
$pieChart = (new PieChartModel)
|
||||
->setTitle('Voteringsstatistik för '.$this->votesSelectedYear)
|
||||
->setAnimated(true)
|
||||
->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');
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ class RiksdagenService
|
||||
string $lastName = '',
|
||||
string $party = ''
|
||||
): JsonResponse {
|
||||
$response = $this->http->get('personlista/', [
|
||||
$response = $this->http->get('personlista/', [
|
||||
'query' => [
|
||||
'iid' => $mp_id,
|
||||
'parti' => $party,
|
||||
@@ -30,8 +30,8 @@ class RiksdagenService
|
||||
'enamn' => $lastName,
|
||||
'utformat' => 'json',
|
||||
'sort' => 'sorteringsnamn',
|
||||
'sortorder' => 'asc'
|
||||
]
|
||||
'sortorder' => 'asc',
|
||||
],
|
||||
])->getBody()->getContents();
|
||||
|
||||
$data = json_decode($response);
|
||||
@@ -44,14 +44,92 @@ class RiksdagenService
|
||||
string $party = '',
|
||||
string $date = '',
|
||||
): JsonResponse {
|
||||
$response = $this->http->get('voteringlista/', [
|
||||
$response = $this->http->get('voteringlista/', [
|
||||
'query' => [
|
||||
'iid' => $mp_id,
|
||||
'rm' => $date,
|
||||
'parti' => $party,
|
||||
'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();
|
||||
|
||||
$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",
|
||||
"vite": "^7.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier-plugin-blade": "^2.1.21"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-linux-x64-gnu": "4.9.5",
|
||||
"@tailwindcss/oxide-linux-x64-gnu": "^4.0.1",
|
||||
@@ -2056,6 +2059,36 @@
|
||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
||||
"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": {
|
||||
"version": "1.1.0",
|
||||
"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",
|
||||
"@tailwindcss/oxide-linux-x64-gnu": "^4.0.1",
|
||||
"lightningcss-linux-x64-gnu": "^1.29.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier-plugin-blade": "^2.1.21"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,30 +6,117 @@
|
||||
Riksdagen App
|
||||
</h1>
|
||||
<p class="text-lg text-gray-600 max-w-2xl mx-auto">
|
||||
Utforska information om riksdagsledamöter, deras röster och uppdrag i Sveriges riksdag
|
||||
Utforska information om riksdagsledamöter, deras röster och
|
||||
uppdrag i Sveriges riksdag
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Navigation Cards -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 max-w-6xl mx-auto">
|
||||
|
||||
<div
|
||||
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 max-w-6xl mx-auto"
|
||||
>
|
||||
<!-- Person Search Card -->
|
||||
<a wire:navigate href="{{ route('person.search') }}" class="group">
|
||||
<div class="bg-white rounded-lg shadow-md hover:shadow-xl transition-all duration-300 transform hover:-translate-y-1 border border-gray-200 overflow-hidden">
|
||||
<div
|
||||
class="bg-white rounded-lg shadow-md hover:shadow-xl transition-all duration-300 transform hover:-translate-y-1 border border-gray-200 overflow-hidden"
|
||||
>
|
||||
<div class="p-6">
|
||||
<div class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center mb-4 group-hover:bg-blue-200 transition-colors">
|
||||
<svg class="w-6 h-6 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
|
||||
<div
|
||||
class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center mb-4 group-hover:bg-blue-200 transition-colors"
|
||||
>
|
||||
<svg
|
||||
class="w-6 h-6 text-blue-600"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-2">Ledamöter</h3>
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-2">
|
||||
Ledamöter
|
||||
</h3>
|
||||
<p class="text-gray-600 mb-4">
|
||||
Sök och utforska information om riksdagsledamöter, deras rösthistorik och uppdrag
|
||||
Sök och utforska information om riksdagsledamöter,
|
||||
deras rösthistorik och uppdrag
|
||||
</p>
|
||||
<div class="flex items-center text-blue-600 group-hover:text-blue-700">
|
||||
<span class="text-sm font-medium">Sök ledamöter</span>
|
||||
<svg class="w-4 h-4 ml-2 transform group-hover:translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
|
||||
<div
|
||||
class="flex items-center text-blue-600 group-hover:text-blue-700"
|
||||
>
|
||||
<span class="text-sm font-medium">
|
||||
Sök ledamöter
|
||||
</span>
|
||||
<svg
|
||||
class="w-4 h-4 ml-2 transform group-hover:translate-x-1 transition-transform"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 5l7 7-7 7"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<!-- 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>
|
||||
</div>
|
||||
</div>
|
||||
@@ -37,16 +124,33 @@
|
||||
</a>
|
||||
|
||||
<!-- 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="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4">
|
||||
<svg class="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path>
|
||||
<div
|
||||
class="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4"
|
||||
>
|
||||
<svg
|
||||
class="w-6 h-6 text-gray-400"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-semibold text-gray-500 mb-2">Propositioner</h3>
|
||||
<h3 class="text-xl font-semibold text-gray-500 mb-2">
|
||||
Propositioner
|
||||
</h3>
|
||||
<p class="text-gray-400 mb-4">
|
||||
Sök och läs propositioner och andra dokument från riksdagen
|
||||
Sök och läs propositioner och andra dokument från
|
||||
riksdagen
|
||||
</p>
|
||||
<div class="flex items-center text-gray-400">
|
||||
<span class="text-sm font-medium">Kommer snart</span>
|
||||
@@ -55,14 +159,30 @@
|
||||
</div>
|
||||
|
||||
<!-- 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="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4">
|
||||
<svg class="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
|
||||
<div
|
||||
class="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4"
|
||||
>
|
||||
<svg
|
||||
class="w-6 h-6 text-gray-400"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-semibold text-gray-500 mb-2">Statistik</h3>
|
||||
<h3 class="text-xl font-semibold text-gray-500 mb-2">
|
||||
Statistik
|
||||
</h3>
|
||||
<p class="text-gray-400 mb-4">
|
||||
Se röststatistik och analyser för partier och ledamöter
|
||||
</p>
|
||||
@@ -72,33 +192,31 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Placeholder Card 3 -->
|
||||
<div class="bg-white rounded-lg shadow-md border border-gray-200 overflow-hidden opacity-60">
|
||||
<div class="p-6">
|
||||
<div class="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4">
|
||||
<svg class="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-semibold text-gray-500 mb-2">Kalender</h3>
|
||||
<p class="text-gray-400 mb-4">
|
||||
Se kommande voteringar och riksdagsmöten
|
||||
</p>
|
||||
<div class="flex items-center text-gray-400">
|
||||
<span class="text-sm font-medium">Kommer snart</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Placeholder Card 4 -->
|
||||
<div class="bg-white rounded-lg shadow-md border border-gray-200 overflow-hidden opacity-60">
|
||||
<div
|
||||
class="bg-white rounded-lg shadow-md border border-gray-200 overflow-hidden opacity-60"
|
||||
>
|
||||
<div class="p-6">
|
||||
<div class="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4">
|
||||
<svg class="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"></path>
|
||||
<div
|
||||
class="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4"
|
||||
>
|
||||
<svg
|
||||
class="w-6 h-6 text-gray-400"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-semibold text-gray-500 mb-2">Partier</h3>
|
||||
<h3 class="text-xl font-semibold text-gray-500 mb-2">
|
||||
Partier
|
||||
</h3>
|
||||
<p class="text-gray-400 mb-4">
|
||||
Utforska partier och deras ståndpunkter i olika frågor
|
||||
</p>
|
||||
@@ -109,14 +227,30 @@
|
||||
</div>
|
||||
|
||||
<!-- 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="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4">
|
||||
<svg class="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
||||
<div
|
||||
class="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mb-4"
|
||||
>
|
||||
<svg
|
||||
class="w-6 h-6 text-gray-400"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-semibold text-gray-500 mb-2">Sök Allmänt</h3>
|
||||
<h3 class="text-xl font-semibold text-gray-500 mb-2">
|
||||
Sök Allmänt
|
||||
</h3>
|
||||
<p class="text-gray-400 mb-4">
|
||||
Sök i alla riksdagens dokument och voteringar
|
||||
</p>
|
||||
@@ -125,7 +259,6 @@
|
||||
</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,43 +88,46 @@
|
||||
@foreach ($persons as $person)
|
||||
<div
|
||||
class="bg-gray-50 rounded-lg p-4 hover:bg-gray-100 transition-colors border border-gray-200">
|
||||
<div class="flex items-center">
|
||||
<img src="{{ $person->bild_url_80 ?? '' }}" alt="{{ $person->tilltalsnamn }}"
|
||||
class="w-16 h-16 rounded-lg object-cover mr-4 border border-gray-300">
|
||||
<div class="flex-1">
|
||||
<a wire:navigate href="{{ route('person.show', $person->intressent_id) }}"
|
||||
class="text-xl font-bold text-blue-600 hover:text-blue-700 transition-colors">
|
||||
{{ $person->tilltalsnamn }} {{ $person->efternamn }} ({{ $person->parti }})
|
||||
</a>
|
||||
<div class="text-gray-600 mt-1 flex items-center gap-2">
|
||||
<img src="{{ App\Enums\Parties::from($person->parti)->logo() }}"
|
||||
width="32">
|
||||
{{ $person->valkrets }}
|
||||
<a wire:navigate href="{{ route('person.show', $person->intressent_id) }}">
|
||||
<div class="flex items-center">
|
||||
<img src="{{ $person->bild_url_80 ?? '' }}" alt="{{ $person->tilltalsnamn }}"
|
||||
class="w-16 h-16 rounded-lg object-cover mr-4 border border-gray-300">
|
||||
<div class="flex-1">
|
||||
<span class="text-xl font-bold text-black transition-colors">
|
||||
{{ $person->tilltalsnamn }} {{ $person->efternamn }}
|
||||
({{ $person->parti }})
|
||||
</span>
|
||||
<div class="text-gray-600 mt-1 flex items-center gap-2">
|
||||
<img src="{{ App\Enums\Parties::from($person->parti)->logo() }}"
|
||||
width="32">
|
||||
{{ $person->valkrets }}
|
||||
</div>
|
||||
<div class="text-sm text-gray-500 mt-1">{{ $person->status }}</div>
|
||||
</div>
|
||||
<div class="text-sm text-gray-500 mt-1">{{ $person->status }}</div>
|
||||
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9 5l7 7-7 7"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9 5l7 7-7 7"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@elseif ($results && (!isset($results->personlista->person) || empty($results->personlista->person)))
|
||||
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-6 max-w-4xl mx-auto">
|
||||
<div class="flex items-center">
|
||||
<svg class="w-5 h-5 text-yellow-600 mr-2" fill="none" stroke="currentColor"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
<span class="text-yellow-800 font-medium">Inga ledamöter hittades med de angivna
|
||||
sökkriterier.</span>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@elseif ($results && (!isset($results->personlista->person) || empty($results->personlista->person)))
|
||||
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-6 max-w-4xl mx-auto">
|
||||
<div class="flex items-center">
|
||||
<svg class="w-5 h-5 text-yellow-600 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
<span class="text-yellow-800 font-medium">Inga ledamöter hittades med de angivna sökkriterier.</span>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,10 @@
|
||||
<?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\Password;
|
||||
use App\Livewire\Settings\Profile;
|
||||
@@ -7,15 +12,14 @@ use App\Livewire\Settings\TwoFactor;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
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('/ledamot', PersonSearch::class)->name('person.search');
|
||||
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')
|
||||
->middleware(['auth', 'verified'])
|
||||
->name('dashboard');
|
||||
|
||||
Reference in New Issue
Block a user