Commit a4b0f3d1 authored by Chanon.u's avatar Chanon.u
Browse files

Add manual response feature

parent 7885f031
<?php
namespace App\Http\Controllers\ManualResponse;
use App\Http\Controllers\Controller;
use App\Models\ManualResponse\MasterResponseTemplates;
use App\Models\ManualResponse\DeclarationRunning;
use Illuminate\Support\Facades\DB;
use SimpleXMLElement;
use DOMDocument;
use Carbon\Carbon;
class GenXmlController extends Controller
{
public function generateXML($templateId, $documentType, $lockData)
{
$template = MasterResponseTemplates::join('mr_master_messages as mm', 'mr_master_response_templates.mid', '=', 'mm.id')
->select('mm.name as messageName', 'mr_master_response_templates.id as templateId', 'mr_master_response_templates.template')
->where('mr_master_response_templates.id', $templateId)
->first();
if (empty($template)) {
return null;
}
$json = json_decode($template['template'], true);
if($json != null){
return $this->genXmlFromTemplate($json, $documentType, $lockData);
}
}
private function genXmlFromTemplate($json, $documentType = '0', $lockData = true, $xml = null, &$xmlData = [])
{
if ($xml === null) {
$rootElement = $json['root'];
$namespace = $json['namespace'];
unset($json['root'], $json['namespace']);
if($namespace !== ''){
$xml = new SimpleXMLElement("<?xml version=\"1.0\" encoding=\"UTF-8\"?><$rootElement xmlns=\"$namespace\"></$rootElement>");
}else{
$xml = new SimpleXMLElement("<?xml version=\"1.0\" encoding=\"UTF-8\"?><$rootElement></$rootElement>");
}
}
foreach ($json as $key => $value) {
if (is_array($value)) {
if (is_numeric($key)) {
$key = 'item' . $key; // dealing with <0/>..<n/> issues
}
$new_object = $xml->addChild($key);
$this->genXmlFromTemplate($value, $documentType, $lockData, $new_object, $xmlData); // Pass by reference
} else {
if (is_numeric($key)) {
$key = 'item' . $key; // dealing with <0/>..<n/> issues
}
if (empty($value)) {
if(!$lockData && in_array($key, ['DeclarationNumber', 'DocumentNumber']) && $documentType !== null){
$value = $this->generateDeclarationNo($documentType);
}else if(!$lockData && $key == 'GoodsTransitionNumber'){
$value = $this->generateGCLNo();
}
if(in_array($key, ['AuditDateTime'])){
$value = Carbon::now()->setTimezone('GMT+7')->format('Y-m-d\TH:i:s');
}
$child = $xml->addChild($key);
$child[0] = ''; // Ensure closed tag for empty value
} else {
$xml->addChild($key, htmlspecialchars($value));
}
$xmlData[$key] = $value; // Collect all tags as editable
}
}
$xmlNoData = [];
foreach($xmlData as $key => $val){
$xmlNoData[$key] = '';
}
//$this->updateXmlValues($this->formatXml($xml->asXML()), $xmlNoData)
return ['xmlContent' => $this->formatXml($xml->asXML()),
'xmlWithData' => $xmlData,
'xmlNoData' => $xmlNoData
];
}
//Convert short tag in case of value is empty to closed tag
private function formatXml($xmlString)
{
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($xmlString);
// Ensure empty tags are closed
$xpath = new \DOMXPath($dom);
foreach ($xpath->query('//*[not(*) and not(text())]') as $node) {
$node->nodeValue = ''; // Set node value to empty string to ensure closed tag
}
return $dom->saveXML();
}
public function updateXmlValues($xmlString, $tagsToUpdate)
{
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->loadXML($xmlString);
foreach ($tagsToUpdate as $tag => $value) {
$nodes = $dom->getElementsByTagName($tag);
foreach ($nodes as $node) {
$node->nodeValue = htmlspecialchars($value);
}
}
return $dom->saveXML();
}
private function generateDeclarationNo($documentType)
{
$currentDate = Carbon::now()->toDateString();
$maxRunningNumber = 999999;
$running = DB::transaction(function () use ($currentDate, $maxRunningNumber, $documentType) {
$runningNumberRecord = DeclarationRunning::lockForUpdate()->where('document_type', $documentType)->first();
if ($runningNumberRecord) {
if ($runningNumberRecord->last_updated_date !== $currentDate) {
// Reset the running number if the date has changed
$runningNumberRecord->running_number = 1;
$runningNumberRecord->last_updated_date = $currentDate;
} elseif ($runningNumberRecord->running_number >= $maxRunningNumber) {
// Reset the running number if it reaches the max value
$runningNumberRecord->running_number = 1;
} else {
// Increment the running number
$runningNumberRecord->running_number += 1;
}
$runningNumberRecord->save();
} else {
// Create a new record if none exists
$runningNumberRecord = DeclarationRunning::create([
'running_number' => 1,
'last_updated_date' => $currentDate,
'document_type' => $documentType,
]);
}
return str_pad($runningNumberRecord->running_number, 6, '0', STR_PAD_LEFT);
});
$tmp_declarationNo = [
"A",
substr($running, 0, 1),
Carbon::now()->format('d'),
$documentType,
substr(Carbon::now()->year + 543, -2),
Carbon::now()->format('m'),
substr($running, -5)
];
return implode('', $tmp_declarationNo);
}
function generateGCLNo(){
$currentDate = Carbon::now()->toDateString();
$maxRunningNumber = 9999999;
$running = DB::transaction(function () use ($currentDate, $maxRunningNumber) {
$runningNumberRecord = DeclarationRunning::lockForUpdate()->where('document_type', "GCL")->first();
if ($runningNumberRecord) {
if ($runningNumberRecord->last_updated_date !== $currentDate) {
// Reset the running number if the date has changed
$runningNumberRecord->running_number = 1;
$runningNumberRecord->last_updated_date = $currentDate;
} elseif ($runningNumberRecord->running_number >= $maxRunningNumber) {
// Reset the running number if it reaches the max value
$runningNumberRecord->running_number = 1;
} else {
// Increment the running number
$runningNumberRecord->running_number += 1;
}
$runningNumberRecord->save();
} else {
// Create a new record if none exists
$runningNumberRecord = DeclarationRunning::create([
'running_number' => 1,
'last_updated_date' => $currentDate,
'document_type' => "GCL",
]);
}
return str_pad($runningNumberRecord->running_number, 7, '0', STR_PAD_LEFT);
});
$tmp_GCLNo = [
substr(Carbon::now()->year + 543, -2),
Carbon::now()->format('m'),
"A",
$running
];
return implode('', $tmp_GCLNo);
}
}
<?php
namespace App\Http\Controllers\ManualResponse;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class ManualResponseController extends Controller
{
public function index()
{
//return view('manual-response/index');
$currentContent = 'ManualResponse';
return view('.home', compact('currentContent'));
}
}
<?php
namespace App\Http\Controllers\ManualResponse;
use App\Models\ManualResponse\UsersConnectSpn;
use App\Http\Controllers\Controller;
class SpnConfigController extends Controller
{
public function init_connection(UsersConnectSpn $user)
{
$username = $user->username;
$password = $user->password;
$link = $user->link;
// Initialize cURL
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$link/spn/login_api.php");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Set the Authorization header for Basic Auth
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Basic ' . base64_encode("$username:$password"),
]);
// Execute cURL request
$response = curl_exec($ch);
$error = curl_error($ch); // Check for errors
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
//dd($response, $error, $httpCode); //Debug response of cURL
curl_close($ch); // Close the cURL handle
if($httpCode == '404'){
return [
'success' => 'false',
'message' => 'This endpoint does not support this feature. Please contact support for upgrade options.'
];
}
if ($error) {
return [
'success' => 'false',
'message' => 'cURL Error: ' . $error
];
}
// Process the response
$decodedResponse = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
session()->flash('error', 'Invalid JSON response');
return null; // Handle invalid JSON appropriately
}
return $decodedResponse; // Return the decoded response
}
}
<?php
namespace App\Http\Livewire\Pages\ManualResponse;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
use App\Http\Controllers\ManualResponse\GenXmlController;
use App\Http\Controllers\ManualResponse\SpnConfigController;
use App\Models\ManualResponse\MasterMessages;
use App\Models\ManualResponse\MasterResponseTemplates;
use App\Models\ManualResponse\MasterDocTypes;
use App\Models\ManualResponse\TabManualResponseLog;
use App\Models\ManualResponse\UsersConnectSpn;
use Carbon\Carbon;
use CURLFile;
class ManualResponse extends Component
{
public $displayCustomizeDiv = false;
public $messageTypes = [];
public $messageId;
public $responseTemplates = [];
public $templateId;
public $templateList;
public $docTypes = [];
public $docType;
public $xmlContent;
public $xmlData = [];
public $xmlWithData = [];
public $activeLoader = false;
public $changeBtnColor;
public $lockData;
public $disableLockData = true;
public $structureXML;
protected $rules = [
'messageId' => 'required|string',
'templateId' => 'required|string'
];
protected $messages = [
'messageId.required' => '*Message cannot be empty.',
'templateId.required' => '*Template cannot be empty.'
];
public function mount()
{
$this->messageTypes = MasterMessages::pluck('value', 'id')->toArray();
$this->docTypes = MasterDocTypes::pluck('name', 'code')->toArray();
$this->changeBtnColor = "bg-[#A020F0] hover:bg-[#B34FEF] text-white font-bold";
$this->lockData = false;
$this->disableLockData = true;
}
public function render()
{
if ($this->messageId != '') {
$this->responseTemplates = MasterResponseTemplates::where('mid', $this->messageId)->get()->mapWithKeys(function ($record) {
$description = $record->description != '' ? ' ' . ' (' . $record->description . ')' : '';
return [$record->id => $record->code . ': ' . $record->name . $description];
})->toArray();
$this->docTypes = MasterDocTypes::where('mid', $this->messageId)->pluck('name', 'code')->toArray();
}
return view('livewire.pages.manual-response.manual-response-index');
}
public function updatedMessageId()
{
$this->templateId = '';
$this->responseTemplates = [];
$this->docTypes = [];
$this->xmlData = [];
$this->xmlContent = '';
$this->displayCustomizeDiv = false;
}
public function updatedXmlTagInputList()
{
if ($this->xmlData === null) {
$this->xmlContent = '';
}
}
public function gotoCustomize()
{
$this->disableLockData = false;
$tmp_xmlData = $this->xmlData;
$this->xmlData = [];
$this->xmlContent = '';
$this->validate();
//Default documentType in case messsage is export/import
if(empty($this->docType)){
if($this->messageId == 1){
$this->docType = 1;
}else if($this->messageId == 2){
$this->docType = 0;
}
}
$xmlGenerator = new GenXmlController();
$xml = $xmlGenerator->generateXML($this->templateId, $this->docType, $this->lockData);
if ($xml == null) {
session()->flash('templateNotFound', 'Template is not found!');
} else {
$this->displayCustomizeDiv = true;
$this->xmlContent = $xml['xmlContent'];
$this->xmlData = $xml['xmlWithData'];
if($this->lockData){
foreach($this->xmlData as $key => $val){
if(isset($tmp_xmlData[$key]) && $key != 'Message'){
$this->xmlData[$key] = $tmp_xmlData[$key];
}
}
}
$this->reGenerateXML();
}
$this->changeBtnColor = "bg-slate-150 font-medium text-slate-800 hover:bg-slate-200 focus:bg-slate-200 active:bg-slate-200/80 rounded-md border border-[#e5e7eb] ";
}
public function reGenerateXML()
{
$xmlGenerator = new GenXmlController();
$xml = $xmlGenerator->updateXmlValues($this->xmlContent, $this->xmlData);
$this->xmlContent = $xml;
}
public function mockUpXML()
{
$this->xmlData = $this->xmlWithData;
}
public function generateAndUploadXml()
{
$this->reGenerateXML();
// Generate XML file from string
$now = Carbon::now();
$filename = 'manual_response_' . $now->format('Ymd_His') . ".xml";
Storage::disk('local')->put($filename, $this->xmlContent);
$filePath = storage_path('app/' . $filename);
$currentUser = Auth::user();
$userConnect = UsersConnectSpn::where('uid', $currentUser->id)->first();
if(!isset($userConnect)){
$this->dispatchBrowserEvent('open-modal', [
'name' => 'alert-modal',
'message' => 'SPN config is not found!',
'status' => 'failed'
]);
return;
}
$spnConfigController = new SpnConfigController();
$spnConfig = $spnConfigController->init_connection($userConnect);
if($spnConfig != null && $spnConfig['success'] == 'true'){
$uid = $spnConfig['uid'];
$ucode = $spnConfig['ucode'];
$ch = curl_init();
$cfile = new CURLFile($filePath, 'application/xml', $filename);
$postData = [
'UID' => $uid,
'UCODE' => $ucode,
'SERVICENAME' => 'imcoreservice',
'ACTION' => 'get_response_customs',
'profilecode' => '',
'API_PLACE_FILE' => 'Y',
'file' => $cfile
];
curl_setopt($ch, CURLOPT_URL, $userConnect->link . "/IE5DEV.shippingnet/data_defaulttemplate.php");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
TabManualResponseLog::create([
'uid' => $currentUser->id,
'title' => 'Send Manual Response',
'detail' => "Username: " . $userConnect->username . "\nLink: " . $userConnect->link,
'xml_content' => base64_encode($this->xmlContent),
'reference_number' => $this->xmlData['ReferenceNumber'],
'declaration_number' => $this->xmlData['DeclarationNumber'],
'link' => $userConnect->link
]);
if ($error) {
//Cannot send response to SPN
$this->dispatchBrowserEvent('open-modal', [
'name' => 'alert-modal',
'message' => 'Cannot send response to SPN',
'status' => 'failed'
]);
} else {
$this->dispatchBrowserEvent('open-modal', [
'name' => 'alert-modal',
'message' => 'Send response successfully',
'status' => 'success'
]);
Storage::disk('local')->delete($filename);
}
}else if($spnConfig != null && $spnConfig['success'] == 'false'){
$this->dispatchBrowserEvent('open-modal', [
'name' => 'alert-modal',
'message' => $spnConfig['message'],
'status' => 'failed'
]);
}else{
//Cannot get UID/UCODE from SPN
$this->dispatchBrowserEvent('open-modal', [
'name' => 'alert-modal',
'message' => 'Cannot connect to SPN',
'status' => 'failed'
]);
}
}
}
<?php
namespace App\Http\Livewire\Pages\User;
use App\Models\User;
use App\Models\ManualResponse\UsersConnectSpn;
use App\Http\Controllers\ManualResponse\SpnConfigController;
use Livewire\Component;
class ConfigManualResponse extends Component
{
public $editUserId;
public $editUsername;
public $usernameSPN;
public $passwordSPN;
public $linkSPN;
public $action;
public function mount($editUserId)
{
$this->editUserId = $editUserId;
$currentUser = User::find($editUserId);
$this->editUsername = $currentUser->first_name;
$userConnectSpn = UsersConnectSpn::where('uid', $editUserId)->first();
if($userConnectSpn){
$this->usernameSPN = $userConnectSpn->username;
$this->passwordSPN = "";
$this->linkSPN = $userConnectSpn->link;
}
}
public function updateConfig()
{
if(empty($this->usernameSPN)){
$this->dispatchBrowserEvent('open-modal', [
'name' => 'alert-modal',
'message' => 'Username must not be empty!',
'status' => 'warning'
]);
return;
}
$userConnectSpn = UsersConnectSpn::where('uid', $this->editUserId)->first();
if($userConnectSpn){
if(empty($this->passwordSPN)){
$this->dispatchBrowserEvent('open-modal', [
'name' => 'alert-modal',
'message' => 'Password must not be empty!',
'status' => 'warning'
]);
return;
}
$userConnectSpn->username = $this->usernameSPN;
$userConnectSpn->password = password_hash($this->passwordSPN, PASSWORD_BCRYPT);
$userConnectSpn->link = $this->linkSPN;
$userConnectSpn->save();
}else{
UsersConnectSpn::create([
'uid' => $this->editUserId,
'username' => $this->usernameSPN,
'password' => '',
"link" => $this->linkSPN
]);
}
$this->dispatchBrowserEvent('open-modal', [
'name' => 'alert-modal',
'message' => 'Update config successfully',
'status' => 'success'
]);
}
public function render()
{
return view('livewire.pages.user.config-manual-response');
}
public function backToMainList()
{
//Use emitTo() to call function on specific component, (emit() will call function on every loaded compoment)
$this->emitTo('pages.user.user-index', 'showUserList', '');
}
public function testConnection()
{
//Use emitTo() to call function on specific component, (emit() will call function on every loaded compoment)
$userConnect = UsersConnectSpn::where('uid', $this->editUserId)->first();
if(!isset($userConnect)){
$this->dispatchBrowserEvent('open-modal', [
'name' => 'alert-modal',
'message' => 'SPN config is not found!',
'status' => 'failed'
]);
return;
}
$spnConfigController = new SpnConfigController();
$spnConfig = $spnConfigController->init_connection($userConnect);
if($spnConfig != null && $spnConfig['success'] == 'true'){
$this->dispatchBrowserEvent('open-modal', [
'name' => 'alert-modal',
'message' => 'Connect to SPN successfully',
'status' => 'success'
]);
}else if($spnConfig != null && $spnConfig['success'] == 'false'){
$this->dispatchBrowserEvent('open-modal', [
'name' => 'alert-modal',
'message' => $spnConfig['message'],
'status' => 'failed'
]);
}else{
//Cannot get UID/UCODE from SPN
$this->dispatchBrowserEvent('open-modal', [
'name' => 'alert-modal',
'message' => 'Cannot connect to SPN',
'status' => 'failed'
]);
}
}
}
...@@ -82,6 +82,17 @@ class UserIndex extends Component ...@@ -82,6 +82,17 @@ class UserIndex extends Component
$this->editUserId = $UserId; $this->editUserId = $UserId;
} }
public function showConfigManualResponseForm($UserId)
{
if (!Auth::user()->hasPermissions(['edit-user'])) {
$this->showNoPermissionModal = TRUE;
return;
}
$this->action = 'configManualResponse';
$this->editUserId = $UserId;
}
public function hideMessage() public function hideMessage()
{ {
$this->showMessage = false; $this->showMessage = false;
......
<?php
namespace App\Models\ManualResponse;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class DeclarationRunning extends Model
{
use HasFactory;
protected $table = 'mr_declaration_running';
protected $fillable = ['document_type', 'running_number', 'last_updated_date'];
}
<?php
namespace App\Models\ManualResponse;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class MasterDocTypes extends Model
{
use HasFactory;
protected $table = 'mr_master_doc_types';
}
<?php
namespace App\Models\ManualResponse;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class MasterMessages extends Model
{
use HasFactory;
protected $table = 'mr_master_messages';
}
<?php
namespace App\Models\ManualResponse;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class MasterResponseTemplates extends Model
{
use HasFactory;
protected $table = 'mr_master_response_templates';
}
<?php
namespace App\Models\ManualResponse;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class TabManualResponseLog extends Model
{
use HasFactory;
protected $table = 'mr_tab_manual_response_log';
protected $fillable = [
'uid',
'title',
'detail',
'xml_content',
'reference_number',
'declaration_number',
'link',
];
}
<?php
namespace App\Models\ManualResponse;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class UsersConnectSpn extends Model
{
use HasFactory;
protected $table = 'mr_users_connect_spn';
protected $fillable = [
'uid',
'username',
'password',
'link',
];
protected $hidden = [
'password'
];
}
...@@ -60,6 +60,7 @@ return [ ...@@ -60,6 +60,7 @@ return [
'engine' => null, 'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([ 'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
PDO::ATTR_PERSISTENT => true,
]) : [], ]) : [],
], ],
......
...@@ -88,18 +88,24 @@ Alpine.data('accordionItem', accordionItem); ...@@ -88,18 +88,24 @@ Alpine.data('accordionItem', accordionItem);
Alpine.start(); Alpine.start();
document.addEventListener('DOMContentLoaded', (event) => { document.addEventListener('DOMContentLoaded', async (event) => {
Prism.highlightAll(); //Prism.highlightAll();
hljs.highlightAll();
}); });
document.addEventListener('livewire:load', function () { document.addEventListener('livewire:load', async function () {
Prism.highlightAll(); //Prism.highlightAll();
hljs.highlightAll();
}); });
Livewire.hook('message.processed', (message, component) => { Livewire.hook('message.processed', (message, component) => {
Prism.highlightAll(); // Find all code blocks inside the component that was updated
component.el.querySelectorAll('pre').forEach((block) => {
hljs.highlightElement(block); // Apply syntax highlighting to the specific element
});
}); });
window.addEventListener('diffResultUpdated', function () { window.addEventListener('diffResultUpdated', async function () {
Prism.highlightAll(); //Prism.highlightAll();
hljs.highlightAll();
}); });
\ No newline at end of file
@props(['name', 'message' => '', 'status' => ''])
<div
x-data="{ showModal: false, name: '{{ $name }}', message: '{{ $message }}', status: '{{ $status }}' }"
x-show="showModal"
x-on:open-modal.window="if ($event.detail.name === name) { showModal = true; message = $event.detail.message; status = $event.detail.status; }"
x-on:close-modal.window="showModal = false" style="display: none">
<div>
<div class="fixed inset-0 z-[100] flex flex-col items-center justify-center overflow-hidden px-4 py-6 sm:px-5"
x-show="showModal" role="dialog" @keydown.window.escape="showModal = false">
<div class="absolute inset-0 bg-slate-900/60 transition-opacity duration-300" @click="showModal = false"
x-show="showModal" x-transition:enter="ease-out" x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100" x-transition:leave="ease-in" x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"></div>
<div class="relative max-w-lg min-w-[500px] rounded-lg bg-white px-4 py-10 text-center transition-opacity duration-300 dark:bg-navy-700 sm:px-5"
x-show="showModal" x-transition:enter="ease-out" x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100" x-transition:leave="ease-in" x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0">
<!-- Conditional SVGs based on status -->
<template x-if="status === 'success'">
<svg xmlns="http://www.w3.org/2000/svg" class="inline size-28 text-success" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
</template>
<template x-if="status === 'warning'">
<svg xmlns="http://www.w3.org/2000/svg" class="inline size-28 text-warning" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
</svg>
</template>
<template x-if="status === 'failed'">
<svg xmlns="http://www.w3.org/2000/svg" class="inline size-28 text-error" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd"
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clip-rule="evenodd"/>
</svg>
</template>
<div class="mt-4">
<p class="mt-2" x-text="message"></p>
<button @click="showModal = false"
class="btn mt-6 bg-gray-200 font-medium text-gray-700 hover:bg-gray-200-focus focus:bg-gray-200-focus active:bg-gray-200-focus/90">
Close
</button>
</div>
</div>
</div>
</div>
</div>
@props(['name'])
<div
x-data="{ showModal: false, name: '{{ $name }}' }"
x-show="showModal"
x-on:open-modal.window="showModal = ($event.detail.name === name); console.log(event.detail)"
x-on:close-modal.window="showModal = false" style="display: none">
<template x-teleport="#x-teleport-target">
<div class="fixed inset-0 z-[100] flex flex-col items-center justify-center overflow-hidden px-4 py-6 sm:px-5"
x-show="showModal" role="dialog" @keydown.window.escape="showModal = false">
<div class="absolute inset-0 bg-slate-900/60 transition-opacity duration-300" @click="showModal = false"
x-show="showModal" x-transition:enter="ease-out" x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100" x-transition:leave="ease-in" x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"></div>
<div class="relative max-w-lg min-w-[500px] rounded-lg bg-white px-4 py-10 text-center transition-opacity duration-300 dark:bg-navy-700 sm:px-5"
x-show="showModal" x-transition:enter="ease-out" x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100" x-transition:leave="ease-in" x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0">
<svg xmlns="http://www.w3.org/2000/svg" class="inline size-28 text-success" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
<div class="mt-4">
<h2 class="text-2xl text-slate-700 dark:text-navy-100"></h2>
@if(isset($message))
<p class="mt-2">{{ $message }}</p>
@endif
<button @click="showModal = false"
class="btn mt-6 font-medium text-slate-700 hover:bg-slate-300/20 active:bg-slate-300/25 border border-slate-300">
Cancel
</button>
<button @click="$wire.emit('test') ; showModal = false"
class="btn mt-6 bg-primary font-medium text-white hover:bg-primary-focus focus:bg-primary-focus active:bg-primary-focus/90">
Confirm
</button>
</div>
</div>
</div>
</template>
</div>
...@@ -97,6 +97,16 @@ ...@@ -97,6 +97,16 @@
</li> </li>
</ul> </ul>
</div> </div>
<div class="rounded-2xl p-3 bg-white w-full mb-2">
<ul >
<li class="mb-1">
<a href="/manual-response/index" :class="activeLink === '/manual-response/index' ? 'bg-primary-focus text-white rounded-xl' : 'text-black'"
class="block py-2 px-4 rounded text-black flex items-center">
<i aria-hidden="true" class="fa-sharp fa-regular fa-paper-plane mr-2"></i> Manual Response
</a>
</li>
</ul>
</div>
<div class="rounded-2xl p-3 bg-white w-full mb-2" x-data="{ open: ['/company', '/role', '/group', '/user', '/format-file-master'].includes(activeLink) }"> <div class="rounded-2xl p-3 bg-white w-full mb-2" x-data="{ open: ['/company', '/role', '/group', '/user', '/format-file-master'].includes(activeLink) }">
<ul > <ul >
......
<div>
<div wire:loading wire:target="{{ $action }}" style="display: none">
<div class="fixed inset-0 z-[100] flex flex-col items-center justify-center overflow-hidden px-4 py-6 sm:px-5">
<div class="absolute inset-0 bg-slate-200/60 backdrop-blur transition-opacity duration-300">
</div>
<div
class="spinner size-16 animate-spin rounded-full border-4 border-[#A020F0] border-r-transparent dark:border-accent dark:border-r-transparent">
</div>
</div>
</div>
</div>
...@@ -82,9 +82,14 @@ ...@@ -82,9 +82,14 @@
<livewire:pages.report.report-index wire:init /> <livewire:pages.report.report-index wire:init />
@break @break
@case('ManualResponse')
<livewire:pages.manual-response.manual-response/>
@break
@default @default
@livewire('code-comparer') @livewire('code-comparer')
@endswitch @endswitch
<x-modals.alert-modal name="alert-modal"></x-modals.alert-modal>
</div> </div>
<script> <script>
// document.addEventListener('livewire:load', function () { // document.addEventListener('livewire:load', function () {
......
<div>
<div id="backgroundDiv" class="w-11/12 mx-auto mt-5 mb-5 pb-5 bg-white/20 rounded-lg shadow-lg backdrop-blur-sm border border-white/30">
<div class="w-10/12 mx-auto pt-5" id="filterDiv">
@if ($errors->any())
{{ $displayCustomizeDiv = false }}
@endif
<h1 class="text-2xl font-bold tracking-tight text-gray-900">Manual Response: Standard Template</h1>
<hr class="my-5">
<div
class="badge space-x-2.5 rounded-full bg-primary text-white shadow-soft shadow-lg shadow-[#1f863680]/50 p-2.5 mb-2">
<div class="size-2 rounded-full bg-current mr-1"></div>
Step 1: Config
</div>
<div class="mx-auto">
<div class="grid grid-cols-1 gap-4 sm:grid-cols-3 pb-1">
<label class="block">
<span class="block text-sm font-medium text-slate-700">Message</span>
<span class="relative mt-1.5 mb-0.1 flex">
<select
class="form-select h-9 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 hover:border-slate-400 focus:border-primary dark:border-navy-450 dark:bg-navy-700 dark:hover:border-navy-400 dark:focus:border-accent"
wire:model="messageId">
<option value="">Select an option</option>
@foreach ($messageTypes as $value => $label)
<option value="{{ $value }}">{{ $label }}</option>
@endforeach
</select>
</span>
@error('messageId')
<span class="text-tiny+ text-error">{{ $message }}</span>
@enderror
</label>
<label class="block">
<span class="block text-sm font-medium text-slate-700">Template</span>
<span class="relative mt-1.5 mb-0.1 flex">
<select
class="form-select h-9 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 hover:border-slate-400 focus:border-primary dark:border-navy-450 dark:bg-navy-700 dark:hover:border-navy-400 dark:focus:border-accent"
wire:model.defer="templateId">
<option value="">Select an option</option>
@foreach ($responseTemplates as $value => $label)
<option value="{{ $value }}">{{ $label }}</option>
@endforeach
</select>
</span>
@error('templateId')
<span class="text-tiny+ text-error">{{ $message }}</span>
@enderror
</label>
<label class="block">
<span class="block text-sm font-medium text-slate-700">Document Type</span>
<span class="relative mt-1.5 mb-0.1 flex">
<select
class="form-select h-9 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 hover:border-slate-400 focus:border-primary dark:border-navy-450 dark:bg-navy-700 dark:hover:border-navy-400 dark:focus:border-accent"
wire:model.defer="docType">
<option value="">Select an option</option>
@foreach ($docTypes as $value => $label)
<option value="{{ $value }}">{{ $label }}</option>
@endforeach
</select>
</span>
@error('docType')
<span class="text-tiny+ text-error">{{ $message }}</span>
@enderror
</label>
</div>
<div class="flex justify-center items-center py-1">
<button class="bg-primary text-white hover:bg-primary-focus py-2 px-4 rounded-md mr-1" wire:click="gotoCustomize">
<i class="fa-solid fa-arrow-right mr-1"></i>Customize</button>
<label class="inline-flex items-center space-x-2">
<input
class="form-checkbox is-basic size-5 rounded border-slate-400/70 checked:bg-primary checked:border-primary hover:border-primary focus:border-primary dark:border-navy-400 dark:checked:bg-accent dark:checked:border-accent dark:hover:border-accent dark:focus:border-accent"
type="checkbox" wire:model.defer="lockData" @if ($disableLockData) disabled @endif />
<p>Lock Data</p>
</label>
</div>
</div>
</div>
@if ($displayCustomizeDiv)
<div class="w-10/12 mx-auto" id="customizeResponseDiv">
<hr class="my-5">
{{-- <h1 class="text-2xl font-bold tracking-tight text-gray-900">1. Customize Template</h1> --}}
<div
class="badge space-x-2.5 rounded-full bg-primary text-white shadow-soft shadow-lg shadow-[#1f863680]/50 p-2.5 mb-2">
<div class="size-2 rounded-full bg-current mr-1"></div>
Step 2: Customize
</div>
@if (session()->has('error'))
<div x-data="{ show: {{ session()->has('error') ? 'true' : 'false' }} }" x-init="setTimeout(() => show = false, 2000)" x-show="show"
x-transition:leave="transition ease-in duration-1000" x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="alert flex rounded-lg bg-error px-4 py-4 text-white sm:px-5">
{{ session('error') }}
</div>
@endif
<div class="flex">
<div class="w-4/12">
<div class="w-12/12 py-1">
@foreach ($xmlData as $key => $value)
<label class="block">
<span class="text-sm font-medium text-slate-700">{{ $key }}</span>
<span class="relative mt-1.5 mb-1.5 flex">
<input
class="form-input peer w-full rounded-lg border border-slate-300 px-3 py-2 placeholder:text-slate-400/70 hover:border-slate-400 focus:border-primary dark:border-navy-450 dark:hover:border-navy-400 dark:focus:border-accent"
type="text" id="{{ $key }}"
wire:model="xmlData.{{ $key }}" value="{{ $value }}"
autocomplete="off" />
</span>
</label>
@endforeach
</div>
</div>
<div class="w-8/12 pl-5">
<div>
<span class="block text-sm font-medium text-slate-700">Preview XML</span>
</div>
<div class="bg-gray-100 p-4 rounded-lg">
<!-- Highlight.js Code Block -->
<pre class="is-scrollbar-hidden max-h-96 overflow-auto rounded-lg" x-data x-init="hljs.highlightElement($el);"><code class="xml">{{ $xmlContent }}</code></pre>
</div>
<div class="flex justify-center items-center pt-1">
<button
class="bg-slate-150 font-medium text-slate-800 hover:bg-slate-200 focus:bg-slate-200 active:bg-slate-200/80 rounded-md border border-[#e5e7eb] py-2 px-4 mr-1"
wire:click="reGenerateXML">
<i class="fa-solid fa-rotate mr-1"></i>Reload XML</button>
</div>
</div>
</div>
<div class="flex justify-center items-center py-1">
<button class="bg-primary text-white hover:bg-primary-focus font-bold py-2 px-4 rounded-md mr-1"
wire:click="generateAndUploadXml"></i>Submit</button>
</div>
</div>
@endif
@include('livewire.loading-component', ['action' => 'generateAndUploadXml, messageId'])
</div>
</div>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment