wip
This commit is contained in:
parent
4c22ab6758
commit
84d8bc1d74
|
|
@ -15,7 +15,7 @@ class ProjectReportGeneratorJob implements ShouldQueue
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
public $timeout = 120;
|
public $timeout = 220;
|
||||||
private ProjectReport $projectReport;
|
private ProjectReport $projectReport;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -47,7 +47,7 @@ public function handle(): void
|
||||||
// Convert commands array to a single string
|
// Convert commands array to a single string
|
||||||
|
|
||||||
$process = new Process($command);
|
$process = new Process($command);
|
||||||
$process->setTimeout(120);
|
$process->setTimeout(220);
|
||||||
$currentPath = '/usr/gnu/bin:/usr/local/bin:/bin:/usr/bin/Users/mfolkerts/anaconda3/bin:/Library/Apple/usr/bin';
|
$currentPath = '/usr/gnu/bin:/usr/local/bin:/bin:/usr/bin/Users/mfolkerts/anaconda3/bin:/Library/Apple/usr/bin';
|
||||||
|
|
||||||
$process->setEnv(['PATH' => $currentPath.':/usr/local/Cellar/pandoc/3.1.8/bin/pandoc']);
|
$process->setEnv(['PATH' => $currentPath.':/usr/local/Cellar/pandoc/3.1.8/bin/pandoc']);
|
||||||
|
|
|
||||||
50
laravel_app/app/Livewire/Forms/MailingForm.php
Normal file
50
laravel_app/app/Livewire/Forms/MailingForm.php
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Forms;
|
||||||
|
|
||||||
|
use App\Models\ProjectMailing;
|
||||||
|
use App\Models\ProjectReport;
|
||||||
|
use Livewire\Attributes\Rule;
|
||||||
|
use Livewire\Form;
|
||||||
|
|
||||||
|
class MailingForm extends Form
|
||||||
|
{
|
||||||
|
#[Rule('required|min:3')]
|
||||||
|
public string $subject = '';
|
||||||
|
|
||||||
|
#[Rule('required')]
|
||||||
|
public string $message = '';
|
||||||
|
|
||||||
|
#[Rule('required')]
|
||||||
|
public array $recipients = [];
|
||||||
|
|
||||||
|
#[Rule('required')]
|
||||||
|
public ProjectReport $report;
|
||||||
|
|
||||||
|
public function setReport(ProjectReport $report)
|
||||||
|
{
|
||||||
|
$this->report = $report;
|
||||||
|
$this->subject = $report->project->mail_subject;
|
||||||
|
$this->message = $report->project->mail_template;
|
||||||
|
$this->recipients = $this->report->project->emailRecipients()->get(['email', 'name'])->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
$this->validate();
|
||||||
|
|
||||||
|
$mailing = $this->report->project->mailings()->create([
|
||||||
|
'subject' => $this->subject,
|
||||||
|
'message' => $this->message,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$mailing->attachments()->create([
|
||||||
|
'name' => $this->report->name,
|
||||||
|
'path' => $this->report->path,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$mailing->recipients()->createMany($this->recipients);
|
||||||
|
|
||||||
|
$this->setReport($this->report);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Livewire\Project;
|
namespace App\Livewire\Project;
|
||||||
|
|
||||||
|
use App\Livewire\Forms\MailingForm;
|
||||||
use App\Models\ProjectReport;
|
use App\Models\ProjectReport;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
@ -10,6 +11,16 @@ class ReportRow extends Component
|
||||||
{
|
{
|
||||||
public ProjectReport $report;
|
public ProjectReport $report;
|
||||||
|
|
||||||
|
public MailingForm $mailingForm;
|
||||||
|
|
||||||
|
public bool $createMailingModal = false;
|
||||||
|
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->mailingForm->setReport($this->report);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public function download()
|
public function download()
|
||||||
{
|
{
|
||||||
$filePath = $this->report->project->download_path . '/' . $this->report->path;
|
$filePath = $this->report->project->download_path . '/' . $this->report->path;
|
||||||
|
|
@ -21,4 +32,9 @@ public function download()
|
||||||
return Storage::download($filePath);
|
return Storage::download($filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function createMailing() {
|
||||||
|
$this->mailingForm->save();
|
||||||
|
$this->reset('createMailingModal');
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,16 @@
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Carbon\CarbonPeriod;
|
use Carbon\CarbonPeriod;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
use Livewire\WithPagination;
|
||||||
use Symfony\Component\Process\Process;
|
use Symfony\Component\Process\Process;
|
||||||
|
|
||||||
class DownloadManager extends Component
|
class DownloadManager extends Component
|
||||||
{
|
{
|
||||||
public $project;
|
use WithPagination;
|
||||||
public $formData;
|
|
||||||
|
|
||||||
|
public $project;
|
||||||
|
|
||||||
|
public $formData;
|
||||||
|
|
||||||
public $showDownloadModal = false;
|
public $showDownloadModal = false;
|
||||||
|
|
||||||
|
|
@ -60,8 +63,10 @@ public function saveDownloads()
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
return view('livewire.projects.download-manager', [
|
$downloads = $this->project->downloads()->orderBy('name', 'desc')->paginate();
|
||||||
'downloads' => $this->project
|
|
||||||
]);
|
return view('livewire.projects.download-manager',
|
||||||
|
compact('downloads')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
use App\Jobs\ProjectReportGeneratorJob;
|
use App\Jobs\ProjectReportGeneratorJob;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
|
use App\Models\ProjectReport;
|
||||||
use App\Rules\AllMosaicsPresentRule;
|
use App\Rules\AllMosaicsPresentRule;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
|
|
@ -77,4 +78,9 @@ public function getDateRangeProperty()
|
||||||
return $begin->format('Y-m-d').' - '.$end->format('Y-m-d');
|
return $begin->format('Y-m-d').' - '.$end->format('Y-m-d');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function deleteReport(ProjectReport $report) {
|
||||||
|
$report->deleteMe();
|
||||||
|
$this->dispatch('refresh');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,139 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Livewire\Reports;
|
|
||||||
|
|
||||||
use App\Models\Report;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
|
||||||
use Laravel\Jetstream\Jetstream;
|
|
||||||
use Livewire\Component;
|
|
||||||
use Symfony\Component\Process\Process;
|
|
||||||
|
|
||||||
class ReportManager extends Component
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The create API token form state.
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
public $createReportForm = [
|
|
||||||
'name' => '',
|
|
||||||
'path' => '',
|
|
||||||
];
|
|
||||||
|
|
||||||
public $processOutput = '';
|
|
||||||
|
|
||||||
public $confirmingReportDeletion = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The ID of the API token being deleted.
|
|
||||||
*
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
public $reportIdBeingDeleted;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mount the component.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new API token.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function createReport()
|
|
||||||
{
|
|
||||||
$this->resetErrorBag();
|
|
||||||
|
|
||||||
Validator::make([
|
|
||||||
'name' => $this->createReportForm['name'],
|
|
||||||
], [
|
|
||||||
'name' => ['required', 'string', 'max:255'],
|
|
||||||
])->validateWithBag('createReport');
|
|
||||||
|
|
||||||
|
|
||||||
$projectFolder = base_path('../');
|
|
||||||
|
|
||||||
$command = [
|
|
||||||
sprintf('%sbuild_report.sh', $projectFolder),
|
|
||||||
sprintf('--filename=%s', $this->createReportForm['name']),
|
|
||||||
];
|
|
||||||
|
|
||||||
// Convert commands array to a single string
|
|
||||||
|
|
||||||
$process = new Process($command);
|
|
||||||
$currentPath = '/usr/gnu/bin:/usr/local/bin:/bin:/usr/bin/Users/mfolkerts/anaconda3/bin:/Library/Apple/usr/bin';
|
|
||||||
|
|
||||||
$process->setEnv(['PATH' => $currentPath.':/usr/local/Cellar/pandoc/3.1.8/bin/pandoc']);
|
|
||||||
$process->setTimeout(36000); // stel een geschikte timeout in
|
|
||||||
$process->start();
|
|
||||||
|
|
||||||
try {
|
|
||||||
$myOutput = [];
|
|
||||||
$process->wait(function ($type, $buffer) use (&$myOutput) {
|
|
||||||
$this->stream(to: 'processOutput', content: $buffer);
|
|
||||||
$myOutput[] = $buffer;
|
|
||||||
logger($buffer);
|
|
||||||
});
|
|
||||||
$this->processOutput = collect($myOutput)->join('\n');
|
|
||||||
|
|
||||||
} catch (ProcessFailedException $exception) {
|
|
||||||
echo $exception->getMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
Report::create(
|
|
||||||
$this->createReportForm
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->createReportForm['name'] = '';
|
|
||||||
|
|
||||||
$this->dispatch('created');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Confirm that the given API token should be deleted.
|
|
||||||
*
|
|
||||||
* @param int $tokenId
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function confirmReportDeletion($reportId)
|
|
||||||
{
|
|
||||||
$this->confirmingReportDeletion = true;
|
|
||||||
|
|
||||||
$this->reportIdBeingDeleted = $reportId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the API token.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function deleteReport()
|
|
||||||
{
|
|
||||||
Report::whereId($this->reportIdBeingDeleted)->first()->delete();
|
|
||||||
|
|
||||||
$this->confirmingReportDeletion = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current user of the application.
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getReportsProperty()
|
|
||||||
{
|
|
||||||
return Report::all();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function render()
|
|
||||||
{
|
|
||||||
return view('livewire.reports.report-manager');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
namespace App\Mail;
|
namespace App\Mail;
|
||||||
|
|
||||||
use App\Models\ProjectMailing;
|
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Mail\Mailable;
|
use Illuminate\Mail\Mailable;
|
||||||
|
|
@ -10,17 +9,16 @@
|
||||||
use Illuminate\Mail\Mailables\Envelope;
|
use Illuminate\Mail\Mailables\Envelope;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
class ReportGenerated extends Mailable
|
class ReportMailer extends Mailable
|
||||||
{
|
{
|
||||||
use Queueable, SerializesModels;
|
use Queueable, SerializesModels;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new message instance.
|
* Create a new message instance.
|
||||||
*/
|
*/
|
||||||
public function __construct(public ProjectMailing $projectMailing)
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -29,12 +27,7 @@ public function __construct(public ProjectMailing $projectMailing)
|
||||||
public function envelope(): Envelope
|
public function envelope(): Envelope
|
||||||
{
|
{
|
||||||
return new Envelope(
|
return new Envelope(
|
||||||
subject: $this->projectMailing->project->mail_subject,
|
subject: 'Report Mailer',
|
||||||
from: [
|
|
||||||
'address' => 'noreply@'.config('app.domain'),
|
|
||||||
'name' => 'Report Generator',
|
|
||||||
],
|
|
||||||
to:$this->projectMailing->recipients->get('mame', 'email')->toArray(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -8,4 +8,9 @@
|
||||||
class ProjectMailingRecipient extends Model
|
class ProjectMailingRecipient extends Model
|
||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'email',
|
||||||
|
'name',
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
|
use Illuminate\Support\Facades\File;
|
||||||
|
|
||||||
class ProjectReport extends Model
|
class ProjectReport extends Model
|
||||||
{
|
{
|
||||||
|
|
@ -68,6 +69,13 @@ public static function getReportDateForYearAndWeek(Project $project, $year, $wee
|
||||||
}
|
}
|
||||||
|
|
||||||
return $reportDay;
|
return $reportDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteMe()
|
||||||
|
{
|
||||||
|
if (File::exists($this->getFullPathName())) {
|
||||||
|
File::delete($this->getFullPathName());
|
||||||
|
}
|
||||||
|
$this->delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1296
laravel_app/composer.lock
generated
1296
laravel_app/composer.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -16,6 +16,7 @@ public function up(): void
|
||||||
$table->foreignId('project_id');
|
$table->foreignId('project_id');
|
||||||
$table->string('subject');
|
$table->string('subject');
|
||||||
$table->text('message');
|
$table->text('message');
|
||||||
|
$table->string('status')->default('pending');
|
||||||
// $table->text('recipients');
|
// $table->text('recipients');
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -89,11 +89,13 @@ private function createChembaProject()
|
||||||
[
|
[
|
||||||
'subject' => 'Chemba 2021-01-01',
|
'subject' => 'Chemba 2021-01-01',
|
||||||
'message' => 'Chemba 2021-01-01',
|
'message' => 'Chemba 2021-01-01',
|
||||||
|
'status' => 'completed', // 'pending
|
||||||
'created_at' => '2021-01-01 00:00:00',
|
'created_at' => '2021-01-01 00:00:00',
|
||||||
'updated_at' => '2021-01-01 00:00:00',
|
'updated_at' => '2021-01-01 00:00:00',
|
||||||
], [
|
], [
|
||||||
'subject' => 'Chemba 2021-01-08',
|
'subject' => 'Chemba 2021-01-08',
|
||||||
'message' => 'Chemba 2021-01-08',
|
'message' => 'Chemba 2021-01-08',
|
||||||
|
'status' => 'completed',
|
||||||
'created_at' => '2021-01-08 00:00:00',
|
'created_at' => '2021-01-08 00:00:00',
|
||||||
'updated_at' => '2021-01-08 00:00:00',
|
'updated_at' => '2021-01-08 00:00:00',
|
||||||
],
|
],
|
||||||
|
|
@ -124,7 +126,8 @@ private function createChembaProject()
|
||||||
'path' => 'chemba/2021-01-08',
|
'path' => 'chemba/2021-01-08',
|
||||||
'created_at' => $mailing->created_at,
|
'created_at' => $mailing->created_at,
|
||||||
'updated_at' => $mailing->updated_at,
|
'updated_at' => $mailing->updated_at,
|
||||||
],]);
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -181,11 +184,13 @@ private function createXinavaneProject()
|
||||||
[
|
[
|
||||||
'subject' => 'Xinavane 2021-01-01',
|
'subject' => 'Xinavane 2021-01-01',
|
||||||
'message' => 'Xinavane 2021-01-01',
|
'message' => 'Xinavane 2021-01-01',
|
||||||
|
'status' => 'completed',
|
||||||
'created_at' => '2021-01-01 00:00:00',
|
'created_at' => '2021-01-01 00:00:00',
|
||||||
'updated_at' => '2021-01-01 00:00:00',
|
'updated_at' => '2021-01-01 00:00:00',
|
||||||
], [
|
], [
|
||||||
'subject' => 'Xinavane 2021-01-08',
|
'subject' => 'Xinavane 2021-01-08',
|
||||||
'message' => 'Xinavane 2021-01-08',
|
'message' => 'Xinavane 2021-01-08',
|
||||||
|
'status' => 'completed',
|
||||||
'created_at' => '2021-01-08 00:00:00',
|
'created_at' => '2021-01-08 00:00:00',
|
||||||
'updated_at' => '2021-01-08 00:00:00',
|
'updated_at' => '2021-01-08 00:00:00',
|
||||||
],
|
],
|
||||||
|
|
@ -217,7 +222,8 @@ private function createXinavaneProject()
|
||||||
'path' => 'xinavane/2021-01-08',
|
'path' => 'xinavane/2021-01-08',
|
||||||
'created_at' => $mailing->created_at,
|
'created_at' => $mailing->created_at,
|
||||||
'updated_at' => $mailing->updated_at,
|
'updated_at' => $mailing->updated_at,
|
||||||
],]);
|
],
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -264,11 +270,13 @@ private function createKakiraProject()
|
||||||
[
|
[
|
||||||
'subject' => 'Kakira 2021-01-01',
|
'subject' => 'Kakira 2021-01-01',
|
||||||
'message' => 'Kakira 2021-01-01',
|
'message' => 'Kakira 2021-01-01',
|
||||||
|
'status' => 'completed',
|
||||||
'created_at' => '2021-01-01 00:00:00',
|
'created_at' => '2021-01-01 00:00:00',
|
||||||
'updated_at' => '2021-01-01 00:00:00',
|
'updated_at' => '2021-01-01 00:00:00',
|
||||||
], [
|
], [
|
||||||
'subject' => 'Kakira 2021-01-08',
|
'subject' => 'Kakira 2021-01-08',
|
||||||
'message' => 'Kakira 2021-01-08',
|
'message' => 'Kakira 2021-01-08',
|
||||||
|
'status' => 'completed',
|
||||||
'created_at' => '2021-01-08 00:00:00',
|
'created_at' => '2021-01-08 00:00:00',
|
||||||
'updated_at' => '2021-01-08 00:00:00',
|
'updated_at' => '2021-01-08 00:00:00',
|
||||||
],
|
],
|
||||||
|
|
@ -279,11 +287,13 @@ private function createKakiraProject()
|
||||||
[
|
[
|
||||||
'name' => 'Martin Folkerts',
|
'name' => 'Martin Folkerts',
|
||||||
'email' => 'martin@sobit.nl',
|
'email' => 'martin@sobit.nl',
|
||||||
|
'status' => 'completed',
|
||||||
'created_at' => $mailing->created_at,
|
'created_at' => $mailing->created_at,
|
||||||
'updated_at' => $mailing->updated_at,
|
'updated_at' => $mailing->updated_at,
|
||||||
], [
|
], [
|
||||||
'name' => 'Timon Weitkamp',
|
'name' => 'Timon Weitkamp',
|
||||||
'email' => 'timon@smartfarmingtech.com',
|
'email' => 'timon@smartfarmingtech.com',
|
||||||
|
'status' => 'completed',
|
||||||
'created_at' => $mailing->created_at,
|
'created_at' => $mailing->created_at,
|
||||||
'updated_at' => $mailing->updated_at,
|
'updated_at' => $mailing->updated_at,
|
||||||
],
|
],
|
||||||
|
|
|
||||||
2
laravel_app/public/vendor/telescope/app.js
vendored
2
laravel_app/public/vendor/telescope/app.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"/app.js": "/app.js?id=140ed4bc5b10bc99492b97668c59272d",
|
"/app.js": "/app.js?id=613c227dfb4d6e1fc4db1b1a90513610",
|
||||||
"/app-dark.css": "/app-dark.css?id=b11fa9a28e9d3aeb8c92986f319b3c44",
|
"/app-dark.css": "/app-dark.css?id=b11fa9a28e9d3aeb8c92986f319b3c44",
|
||||||
"/app.css": "/app.css?id=b3ccfbe68f24cff776f83faa8dead721"
|
"/app.css": "/app.css?id=b3ccfbe68f24cff776f83faa8dead721"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,4 @@ htabs(Alpine)
|
||||||
|
|
||||||
window.Alpine = Alpine
|
window.Alpine = Alpine
|
||||||
|
|
||||||
document.addEventListener("alpine:init", () => {
|
|
||||||
console.log("Alpine Initialized")
|
|
||||||
});
|
|
||||||
|
|
||||||
Livewire.start();
|
Livewire.start();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
<span x-on:click="dialogOpen = false">
|
||||||
|
{{ $slot }}
|
||||||
|
</span>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<div class="p-4 py-4 px-4 -mx-8 -mb-8 mt-8 bg-slate-100">
|
||||||
|
<div class="flex justify-end gap-4">
|
||||||
|
{{ $slot }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<div
|
||||||
|
x-data="{ dialogOpen: false }"
|
||||||
|
x-modelable="dialogOpen"
|
||||||
|
{{ $attributes }}
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
{{ $slot }}
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
<span x-on:click="dialogOpen = true" tabindex="-1">
|
||||||
|
{{ $slot }}
|
||||||
|
</span>
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
<template x-teleport="body">
|
||||||
|
<div
|
||||||
|
x-dialog
|
||||||
|
x-model="dialogOpen"
|
||||||
|
style="display: none"
|
||||||
|
class="fixed inset-0 overflow-y-auto z-10 text-left"
|
||||||
|
>
|
||||||
|
<!-- Overlay -->
|
||||||
|
<div x-dialog:overlay x-transition:enter.opacity class="fixed inset-0 bg-black/25"></div>
|
||||||
|
|
||||||
|
<!-- Panel -->
|
||||||
|
<div class="relative min-h-screen flex items-center justify-center p-4">
|
||||||
|
<div
|
||||||
|
x-dialog:panel
|
||||||
|
x-transition.in
|
||||||
|
class="relative max-w-xl w-full bg-white rounded-xl shadow-lg overflow-y-auto"
|
||||||
|
>
|
||||||
|
<!-- Close Button -->
|
||||||
|
<div class="absolute top-0 right-0 pt-4 pr-4">
|
||||||
|
<button type="button" x-on:click="$dialog.close()" class="bg-gray-50 rounded-lg p-2 text-gray-600 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2">
|
||||||
|
<span class="sr-only">Close modal</span>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Panel -->
|
||||||
|
<div class="p-8">
|
||||||
|
{{ $slot }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -19,11 +19,12 @@
|
||||||
<div class="col-span-6 sm:col-span-4">
|
<div class="col-span-6 sm:col-span-4">
|
||||||
<div
|
<div
|
||||||
x-data="{
|
x-data="{
|
||||||
|
value: @entangle('formData.dateRange'),
|
||||||
init() {
|
init() {
|
||||||
let picker = flatpickr(this.$refs.picker, {
|
let picker = flatpickr(this.$refs.picker, {
|
||||||
mode: 'range',
|
mode: 'range',
|
||||||
dateFormat: 'Y/m/d',
|
dateFormat: 'Y/m/d',
|
||||||
defaultDate: this.$wire.formData.dateRange,
|
defaultDate: this.value,
|
||||||
onChange: (date, dateString) => {
|
onChange: (date, dateString) => {
|
||||||
this.value = dateString.split(' to ');
|
this.value = dateString.split(' to ');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
<button type="button" x-menu:button {{ $attributes }}>
|
||||||
|
{{ $slot }}
|
||||||
|
</button>
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
<span x-on:click="menuOpen = false">
|
||||||
|
{{ $slot }}
|
||||||
|
</span>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<div x-data="{ menuOpen: false }">
|
||||||
|
<div x-menu x-model="menuOpen" class="relative flex items-center">
|
||||||
|
{{ $slot }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
13
laravel_app/resources/views/components/menu/item.blade.php
Normal file
13
laravel_app/resources/views/components/menu/item.blade.php
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
x-menu:item
|
||||||
|
x-bind:class="{
|
||||||
|
'bg-slate-100 text-gray-900': $menuItem.isActive,
|
||||||
|
'text-gray-600': ! $menuItem.isActive,
|
||||||
|
'opacity-50 cursor-not-allowed': $menuItem.isDisabled,
|
||||||
|
}"
|
||||||
|
class="flex items-center gap-2 w-full px-3 py-2 text-left text-sm hover:bg-slate-50 disabled:text-gray-500 transition-colors"
|
||||||
|
{{ $attributes }}
|
||||||
|
>
|
||||||
|
{{ $slot }}
|
||||||
|
</button>
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
<div
|
||||||
|
x-menu:items
|
||||||
|
x-transition:enter.origin.top.right
|
||||||
|
x-anchor.bottom-start="document.getElementById($id('alpine-menu-button'))"
|
||||||
|
class="w-48 z-10 bg-white border border-gray-200 divide-y divide-gray-100 rounded-md shadow-md py-1 outline-none"
|
||||||
|
x-cloak
|
||||||
|
>
|
||||||
|
{{ $slot }}
|
||||||
|
</div>
|
||||||
41
laravel_app/resources/views/livewire/pagination.blade.php
Normal file
41
laravel_app/resources/views/livewire/pagination.blade.php
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
@if ($paginator->hasPages())
|
||||||
|
<nav role="navigation" aria-label="Pagination Navigation" class="flex gap-2">
|
||||||
|
<span>
|
||||||
|
{{-- Previous Page Link --}}
|
||||||
|
@if ($paginator->onFirstPage())
|
||||||
|
<button type="button" class="rounded-lg border px-3 py-2 bg-white font-semibold text-sm text-gray-700 hover:bg-gray-100 disabled:bg-gray-50 disabled:opacity-75 disabled:cursor-not-allowed disabled:text-gray-500" disabled>
|
||||||
|
Prev
|
||||||
|
</button>
|
||||||
|
@else
|
||||||
|
@if(method_exists($paginator,'getCursorName'))
|
||||||
|
<button type="button" dusk="previousPage" wire:key="cursor-{{ $paginator->getCursorName() }}-{{ $paginator->previousCursor()->encode() }}" wire:click="setPage('{{$paginator->previousCursor()->encode()}}','{{ $paginator->getCursorName() }}')" wire:loading.attr="disabled" class="rounded-lg border px-3 py-2 bg-white font-semibold text-sm text-gray-700 hover:bg-gray-100 disabled:bg-gray-50 disabled:opacity-75 disabled:cursor-not-allowed disabled:text-gray-500">
|
||||||
|
Prev
|
||||||
|
</button>
|
||||||
|
@else
|
||||||
|
<button type="button" wire:click="previousPage('{{ $paginator->getPageName() }}')" wire:loading.attr="disabled" dusk="previousPage{{ $paginator->getPageName() == 'page' ? '' : '.' . $paginator->getPageName() }}" class="rounded-lg border px-3 py-2 bg-white font-semibold text-sm text-gray-700 hover:bg-gray-100 disabled:bg-gray-50 disabled:opacity-75 disabled:cursor-not-allowed disabled:text-gray-500">
|
||||||
|
Prev
|
||||||
|
</button>
|
||||||
|
@endif
|
||||||
|
@endif
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
{{-- Next Page Link --}}
|
||||||
|
@if ($paginator->hasMorePages())
|
||||||
|
@if(method_exists($paginator,'getCursorName'))
|
||||||
|
<button type="button" dusk="nextPage" wire:key="cursor-{{ $paginator->getCursorName() }}-{{ $paginator->nextCursor()->encode() }}" wire:click="setPage('{{$paginator->nextCursor()->encode()}}','{{ $paginator->getCursorName() }}')" wire:loading.attr="disabled" class="rounded-lg border px-3 py-2 bg-white font-semibold text-sm text-gray-700 hover:bg-gray-100 disabled:bg-gray-50 disabled:opacity-75 disabled:cursor-not-allowed disabled:text-gray-500">
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
@else
|
||||||
|
<button type="button" wire:click="nextPage('{{ $paginator->getPageName() }}')" wire:loading.attr="disabled" dusk="nextPage{{ $paginator->getPageName() == 'page' ? '' : '.' . $paginator->getPageName() }}" class="rounded-lg border px-3 py-2 bg-white font-semibold text-sm text-gray-700 hover:bg-gray-100 disabled:bg-gray-50 disabled:opacity-75 disabled:cursor-not-allowed disabled:text-gray-500">
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
@endif
|
||||||
|
@else
|
||||||
|
<button type="button" class="rounded-lg border px-3 py-2 bg-white font-semibold text-sm text-gray-700 hover:bg-gray-100 disabled:bg-gray-50 disabled:opacity-75 disabled:cursor-not-allowed disabled:text-gray-500" disabled>
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
@endif
|
||||||
|
</span>
|
||||||
|
</nav>
|
||||||
|
@endif
|
||||||
|
|
@ -11,10 +11,158 @@
|
||||||
lindsay.walton@example.com
|
lindsay.walton@example.com
|
||||||
</td>
|
</td>
|
||||||
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">Member</td>
|
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">Member</td>
|
||||||
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 lg:pr-8">
|
<td class="py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 lg:pr-8 flex justify-end">
|
||||||
@if($report->status === 'success')
|
<x-menu>
|
||||||
<x-button wire:click="download">Download</x-button>
|
<x-menu.button>
|
||||||
@endif
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
||||||
|
stroke="currentColor" class="w-6 h-6">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="M6.75 12a.75.75 0 11-1.5 0 .75.75 0 011.5 0zM12.75 12a.75.75 0 11-1.5 0 .75.75 0 011.5 0zM18.75 12a.75.75 0 11-1.5 0 .75.75 0 011.5 0z"/>
|
||||||
|
</svg>
|
||||||
|
</x-menu.button>
|
||||||
|
|
||||||
|
<x-menu.items>
|
||||||
|
|
||||||
|
<x-menu.close>
|
||||||
|
<x-menu.item wire:click="download">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
||||||
|
stroke="currentColor" class="w-4 h-4">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="m20.25 7.5-.625 10.632a2.25 2.25 0 0 1-2.247 2.118H6.622a2.25 2.25 0 0 1-2.247-2.118L3.75 7.5m8.25 3v6.75m0 0-3-3m3 3 3-3M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125Z"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
Download
|
||||||
|
</x-menu.item>
|
||||||
|
</x-menu.close>
|
||||||
|
|
||||||
|
<x-dialog>
|
||||||
|
<x-dialog.open>
|
||||||
|
<x-menu.close>
|
||||||
|
<x-menu.item>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke="currentColor" class="w-4 h-4">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="M9 3.75H6.912a2.25 2.25 0 0 0-2.15 1.588L2.35 13.177a2.25 2.25 0 0 0-.1.661V18a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18v-4.162c0-.224-.034-.447-.1-.661L19.24 5.338a2.25 2.25 0 0 0-2.15-1.588H15M2.25 13.5h3.86a2.25 2.25 0 0 1 2.012 1.244l.256.512a2.25 2.25 0 0 0 2.013 1.244h3.218a2.25 2.25 0 0 0 2.013-1.244l.256-.512a2.25 2.25 0 0 1 2.013-1.244h3.859M12 3v8.25m0 0-3-3m3 3 3-3"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
Create Mail
|
||||||
|
</x-menu.item>
|
||||||
|
</x-menu.close>
|
||||||
|
</x-dialog.open>
|
||||||
|
|
||||||
|
<x-dialog.panel wire:model="createMailingModal">
|
||||||
|
<form wire:submit="createMailing" class="flex flex-col gap-4">
|
||||||
|
<h2 class="text-3xl font-bold mb-1">@lang('Create report email')</h2>
|
||||||
|
|
||||||
|
<hr class="w-[75%]">
|
||||||
|
|
||||||
|
<label class="flex flex-col gap-2">
|
||||||
|
@lang('Recipients')
|
||||||
|
@foreach($mailingForm->recipients as $recipient)
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center gap-x-1.5 rounded-md bg-gray-100 px-2 py-1 text-xs font-medium text-gray-600">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
|
||||||
|
class="w-4 h-4">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
|
||||||
|
[{{ $recipient['name'] }}] {{ $recipient['email'] }}
|
||||||
|
</span>
|
||||||
|
@endforeach
|
||||||
|
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="flex flex-col gap-2">
|
||||||
|
@lang('Subject')
|
||||||
|
<input autofocus wire:model="mailingForm.subject"
|
||||||
|
class="px-3 py-2 border font-normal rounded-lg border-slate-300 read-only:opacity-50 read-only:cursor-not-allowed">
|
||||||
|
@error('mailingForm.subject')
|
||||||
|
<div class="text-sm text-red-500 font-normal">{{ $message }}</div>@enderror
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="flex flex-col gap-2">
|
||||||
|
@lang('Content')
|
||||||
|
<textarea wire:model="mailingForm.message" rows="5"
|
||||||
|
class="px-3 py-2 border font-normal rounded-lg border-slate-300 read-only:opacity-50 read-only:cursor-not-allowed"></textarea>
|
||||||
|
@error('mailingForm.message')
|
||||||
|
<div class="text-sm text-red-500 font-normal">{{ $message }}</div>@enderror
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="flex flex-col gap-2">
|
||||||
|
@lang('Report')
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center gap-x-1.5 rounded-md bg-gray-100 px-2 py-1 text-xs font-medium text-gray-600">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
|
||||||
|
class="w-4 h-4">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="M13.19 8.688a4.5 4.5 0 0 1 1.242 7.244l-4.5 4.5a4.5 4.5 0 0 1-6.364-6.364l1.757-1.757m13.35-.622 1.757-1.757a4.5 4.5 0 0 0-6.364-6.364l-4.5 4.5a4.5 4.5 0 0 0 1.242 7.244"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
{{ $report->name }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<x-dialog.footer>
|
||||||
|
<x-dialog.close>
|
||||||
|
<button type="button"
|
||||||
|
class="text-center rounded-xl bg-slate-300 text-slate-800 px-6 py-2 font-semibold">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</x-dialog.close>
|
||||||
|
<x-dialog.close>
|
||||||
|
<button type="submit"
|
||||||
|
class="text-center rounded-xl bg-blue-500 text-white px-6 py-2 font-semibold disabled:cursor-not-allowed disabled:opacity-50">
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</x-dialog.close>
|
||||||
|
</x-dialog.footer>
|
||||||
|
</form>
|
||||||
|
</x-dialog.panel>
|
||||||
|
</x-dialog>
|
||||||
|
|
||||||
|
<x-dialog>
|
||||||
|
<x-dialog.open>
|
||||||
|
<x-menu.item>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"
|
||||||
|
class="w-4 h-4">
|
||||||
|
<path fill-rule="evenodd"
|
||||||
|
d="M8.75 1A2.75 2.75 0 006 3.75v.443c-.795.077-1.584.176-2.365.298a.75.75 0 10.23 1.482l.149-.022.841 10.518A2.75 2.75 0 007.596 19h4.807a2.75 2.75 0 002.742-2.53l.841-10.52.149.023a.75.75 0 00.23-1.482A41.03 41.03 0 0014 4.193V3.75A2.75 2.75 0 0011.25 1h-2.5zM10 4c.84 0 1.673.025 2.5.075V3.75c0-.69-.56-1.25-1.25-1.25h-2.5c-.69 0-1.25.56-1.25 1.25v.325C8.327 4.025 9.16 4 10 4zM8.58 7.72a.75.75 0 00-1.5.06l.3 7.5a.75.75 0 101.5-.06l-.3-7.5zm4.34.06a.75.75 0 10-1.5-.06l-.3 7.5a.75.75 0 101.5.06l.3-7.5z"
|
||||||
|
clip-rule="evenodd"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
Delete
|
||||||
|
</x-menu.item>
|
||||||
|
</x-dialog.open>
|
||||||
|
|
||||||
|
|
||||||
|
<x-dialog.panel>
|
||||||
|
<div class="flex flex-col gap-6">
|
||||||
|
<h2 class="font-semibold text-3xl">Are you sure you?</h2>
|
||||||
|
<h2 class="text-lg text-slate-700">This operation is permanent and can not be reversed.</h2>
|
||||||
|
<x-dialog.footer>
|
||||||
|
<x-dialog.close>
|
||||||
|
<button type="button"
|
||||||
|
class="text-center rounded-xl bg-slate-300 text-slate-800 px-6 py-2 font-semibold">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</x-dialog.close>
|
||||||
|
|
||||||
|
<x-dialog.close>
|
||||||
|
<button wire:click="$parent.deleteReport('{{ $report->id }}')" type="button"
|
||||||
|
class="text-center rounded-xl bg-red-500 text-white px-6 py-2 font-semibold disabled:cursor-not-allowed disabled:opacity-50">
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</x-dialog.close>
|
||||||
|
</x-dialog.footer>
|
||||||
|
</div>
|
||||||
|
</x-dialog.panel>
|
||||||
|
</x-dialog>
|
||||||
|
</x-menu.items>
|
||||||
|
</x-menu>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
<div class="flex flex-col gap-8">
|
||||||
|
<div class="flex flex-col sm:grid grid-cols-8 gap-2">
|
||||||
|
<div class="relative text-sm text-gray-800 col-span-3">
|
||||||
|
<div class="absolute pl-2 left-0 top-0 bottom-0 flex items-center pointer-events-none text-gray-500">
|
||||||
|
<x-icon.magnifying-glass />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="text" placeholder="Search email or order #" class="block w-full rounded-lg border-0 py-1.5 pl-10 text-gray-900 ring-1 ring-inset ring-gray-200 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex gap-2 justify-end col-span-5">
|
||||||
|
<div class="hidden sm:flex">
|
||||||
|
<button type="button" class="flex items-center gap-2 rounded-lg border px-3 py-1.5 bg-white font-medium text-sm text-gray-700 hover:bg-gray-200">
|
||||||
|
<x-icon.arrow-down-tray />
|
||||||
|
|
||||||
|
Export
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="overflow-x-auto w-full">
|
||||||
|
<div class="relative animate-pulse min-w-[49.5rem]">
|
||||||
|
<div class="p-3">
|
||||||
|
<div class="w-full bg-gray-100 rounded-lg"> </div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="min-w-full table-fixed divide-y divide-gray-300 text-gray-800">
|
||||||
|
<tbody class="divide-y divide-gray-200 bg-white text-gray-700">
|
||||||
|
@foreach (range(0, 5) as $i)
|
||||||
|
<tr>
|
||||||
|
<td class="whitespace-nowrap p-3 text-sm">
|
||||||
|
<div class="w-full bg-gray-200 rounded-lg"> </div>
|
||||||
|
</td>
|
||||||
|
<td class="whitespace-nowrap p-3 text-sm" colspan="2">
|
||||||
|
<div class="w-full bg-gray-200 rounded-lg"> </div>
|
||||||
|
</td>
|
||||||
|
<td class="whitespace-nowrap p-3 text-sm" colspan="3">
|
||||||
|
<div class="w-full bg-gray-200 rounded-lg"> </div>
|
||||||
|
</td>
|
||||||
|
<td class="whitespace-nowrap p-3 text-sm">
|
||||||
|
<div class="w-full bg-gray-200 rounded-lg"> </div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -39,7 +39,7 @@ class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6 lg
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="divide-y divide-gray-200 bg-white">
|
<tbody class="divide-y divide-gray-200 bg-white">
|
||||||
@foreach($project->downloads()->orderBy('name', 'desc')->get() as $download)
|
@foreach($downloads as $download)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6 lg:pl-8">{{ $download->name }}</td>
|
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6 lg:pl-8">{{ $download->name }}</td>
|
||||||
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
|
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
|
||||||
|
|
@ -52,6 +52,14 @@ class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6 lg
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="pt-4 flex justify-between items-center">
|
||||||
|
<div class="text-gray-700 text-sm">
|
||||||
|
Results: {{ \Illuminate\Support\Number::format($downloads->total()) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ $downloads->links('livewire.pagination') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
<div class="flex flex-col gap-8">
|
||||||
|
<div class="flex flex-col sm:grid grid-cols-8 gap-2">
|
||||||
|
<div class="relative text-sm text-gray-800 col-span-3">
|
||||||
|
<div class="absolute pl-2 left-0 top-0 bottom-0 flex items-center pointer-events-none text-gray-500">
|
||||||
|
<x-icon.magnifying-glass />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="text" placeholder="Search email or order #" class="block w-full rounded-lg border-0 py-1.5 pl-10 text-gray-900 ring-1 ring-inset ring-gray-200 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex gap-2 justify-end col-span-5">
|
||||||
|
<div class="hidden sm:flex">
|
||||||
|
<button type="button" class="flex items-center gap-2 rounded-lg border px-3 py-1.5 bg-white font-medium text-sm text-gray-700 hover:bg-gray-200">
|
||||||
|
<x-icon.arrow-down-tray />
|
||||||
|
|
||||||
|
Export
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="overflow-x-auto w-full">
|
||||||
|
<div class="relative animate-pulse min-w-[49.5rem]">
|
||||||
|
<div class="p-3">
|
||||||
|
<div class="w-full bg-gray-100 rounded-lg"> </div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="min-w-full table-fixed divide-y divide-gray-300 text-gray-800">
|
||||||
|
<tbody class="divide-y divide-gray-200 bg-white text-gray-700">
|
||||||
|
@foreach (range(0, 5) as $i)
|
||||||
|
<tr>
|
||||||
|
<td class="whitespace-nowrap p-3 text-sm">
|
||||||
|
<div class="w-full bg-gray-200 rounded-lg"> </div>
|
||||||
|
</td>
|
||||||
|
<td class="whitespace-nowrap p-3 text-sm" colspan="2">
|
||||||
|
<div class="w-full bg-gray-200 rounded-lg"> </div>
|
||||||
|
</td>
|
||||||
|
<td class="whitespace-nowrap p-3 text-sm" colspan="3">
|
||||||
|
<div class="w-full bg-gray-200 rounded-lg"> </div>
|
||||||
|
</td>
|
||||||
|
<td class="whitespace-nowrap p-3 text-sm">
|
||||||
|
<div class="w-full bg-gray-200 rounded-lg"> </div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -1,20 +1,22 @@
|
||||||
<div>
|
<div>
|
||||||
<x-tab-section>
|
<div class="px-4 sm:px-6 lg:px-8">
|
||||||
<x-slot name="title">Mailing Details</x-slot>
|
<div class="mt-8 flow-root">
|
||||||
<x-slot name="description">...</x-slot>
|
<div class="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
||||||
|
<div class="inline-block min-w-full py-2 align-middle mb-10">
|
||||||
<x-slot name="form">
|
|
||||||
<div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
|
|
||||||
<table class="min-w-full divide-y divide-gray-300">
|
<table class="min-w-full divide-y divide-gray-300">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col" class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-0">
|
<th scope="col"
|
||||||
|
class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6 lg:pl-8">
|
||||||
Id
|
Id
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">Created</th>
|
<th scope="col"
|
||||||
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">Subject</th>
|
class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6 lg:pl-8">@lang('Subject')</th>
|
||||||
|
<th scope="col"
|
||||||
|
class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6 lg:pl-8">@lang('Status')</th>
|
||||||
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">#</th>
|
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">#</th>
|
||||||
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">Attachment
|
<th scope="col"
|
||||||
|
class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">@lang('Attachment')
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" class="relative py-3.5 pl-3 pr-4 sm:pr-0">
|
<th scope="col" class="relative py-3.5 pl-3 pr-4 sm:pr-0">
|
||||||
<span class="sr-only">Edit</span>
|
<span class="sr-only">Edit</span>
|
||||||
|
|
@ -24,9 +26,11 @@
|
||||||
<tbody class="divide-y divide-gray-200">
|
<tbody class="divide-y divide-gray-200">
|
||||||
@foreach($project->mailings as $mail)
|
@foreach($project->mailings as $mail)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-0">{{ $mail->id }}</td>
|
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6 lg:pl-8">{{ $mail->id }}</td>
|
||||||
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ $mail->created_at }} </td>
|
|
||||||
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ $mail->subject }}</td>
|
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ $mail->subject }}</td>
|
||||||
|
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
|
||||||
|
<x-badge :status="$mail->status"></x-badge>
|
||||||
|
</td>
|
||||||
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ $mail->recipients()->count() }}</td>
|
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ $mail->recipients()->count() }}</td>
|
||||||
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ $mail->attachments()->pluck('name')->join( ', ') }}</td>
|
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ $mail->attachments()->pluck('name')->join( ', ') }}</td>
|
||||||
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
|
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
|
||||||
|
|
@ -40,10 +44,8 @@ class="text-indigo-600 hover:text-indigo-900">Show
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</x-slot>
|
|
||||||
|
|
||||||
|
|
||||||
</x-tab-section>
|
|
||||||
<x-modal wire:model.live="mailingDetailsModal">
|
<x-modal wire:model.live="mailingDetailsModal">
|
||||||
<x-form-modal submit="saveProject">
|
<x-form-modal submit="saveProject">
|
||||||
<x-slot name="title">
|
<x-slot name="title">
|
||||||
|
|
@ -52,7 +54,8 @@ class="text-indigo-600 hover:text-indigo-900">Show
|
||||||
|
|
||||||
<x-slot name="description">
|
<x-slot name="description">
|
||||||
<x-label for="created_at" value="{{ __('Created') }}"/>
|
<x-label for="created_at" value="{{ __('Created') }}"/>
|
||||||
<x-label id="created_at" value="{{ \Carbon\Carbon::parse($formData['created_at'])->format('Y-m-d H:i') }}"/>
|
<x-label id="created_at"
|
||||||
|
value="{{ \Carbon\Carbon::parse($formData['created_at'])->format('Y-m-d H:i') }}"/>
|
||||||
</x-slot>
|
</x-slot>
|
||||||
|
|
||||||
<x-slot name="form">
|
<x-slot name="form">
|
||||||
|
|
@ -60,14 +63,17 @@ class="text-indigo-600 hover:text-indigo-900">Show
|
||||||
<x-label for="recipients" value="{{ __('Recipients') }}"/>
|
<x-label for="recipients" value="{{ __('Recipients') }}"/>
|
||||||
@foreach($formData['recipients'] as $key => $recipient)
|
@foreach($formData['recipients'] as $key => $recipient)
|
||||||
<div class="col-span-6 sm:col-span-4">
|
<div class="col-span-6 sm:col-span-4">
|
||||||
<x-label class="inline-block" for="recipients" value="{{ $recipient['name'] }}"/>
|
<x-label class="inline-block" for="recipients"
|
||||||
<x-label class="inline-block" for="recipients" value="<{{ $recipient['email'] }}>"/>
|
value="{{ $recipient['name'] }}"/>
|
||||||
|
<x-label class="inline-block" for="recipients"
|
||||||
|
value="<{{ $recipient['email'] }}>"/>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6">
|
<div class="col-span-6">
|
||||||
<x-label for="subject" value="{{ __('Subject') }}"/>
|
<x-label for="subject" value="{{ __('Subject') }}"/>
|
||||||
<x-input id="subject" type="text" class="mt-1 block w-full" disabled wire:model="formData.subject"/>
|
<x-input id="subject" type="text" class="mt-1 block w-full" disabled
|
||||||
|
wire:model="formData.subject"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6">
|
<div class="col-span-6">
|
||||||
<x-label for="message" value="{{ __('Message') }}"/>
|
<x-label for="message" value="{{ __('Message') }}"/>
|
||||||
|
|
@ -88,7 +94,8 @@ class="mt-1 block w-full"
|
||||||
@else
|
@else
|
||||||
@foreach($formData['attachments'] as $key => $attachment)
|
@foreach($formData['attachments'] as $key => $attachment)
|
||||||
<div class="col-span-6">
|
<div class="col-span-6">
|
||||||
<x-label class="inline-block" for="recipients" value="{{ $attachment['name'] }}"/>
|
<x-label class="inline-block" for="recipients"
|
||||||
|
value="{{ $attachment['name'] }}"/>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
@endempty
|
@endempty
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
<div class="flex flex-col gap-8">
|
||||||
|
<div class="flex flex-col sm:grid grid-cols-8 gap-2">
|
||||||
|
<div class="relative text-sm text-gray-800 col-span-3">
|
||||||
|
<div class="absolute pl-2 left-0 top-0 bottom-0 flex items-center pointer-events-none text-gray-500">
|
||||||
|
<x-icon.magnifying-glass />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="text" placeholder="Search email or order #" class="block w-full rounded-lg border-0 py-1.5 pl-10 text-gray-900 ring-1 ring-inset ring-gray-200 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex gap-2 justify-end col-span-5">
|
||||||
|
<div class="hidden sm:flex">
|
||||||
|
<button type="button" class="flex items-center gap-2 rounded-lg border px-3 py-1.5 bg-white font-medium text-sm text-gray-700 hover:bg-gray-200">
|
||||||
|
<x-icon.arrow-down-tray />
|
||||||
|
|
||||||
|
Export
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="overflow-x-auto w-full">
|
||||||
|
<div class="relative animate-pulse min-w-[49.5rem]">
|
||||||
|
<div class="p-3">
|
||||||
|
<div class="w-full bg-gray-100 rounded-lg"> </div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="min-w-full table-fixed divide-y divide-gray-300 text-gray-800">
|
||||||
|
<tbody class="divide-y divide-gray-200 bg-white text-gray-700">
|
||||||
|
@foreach (range(0, 5) as $i)
|
||||||
|
<tr>
|
||||||
|
<td class="whitespace-nowrap p-3 text-sm">
|
||||||
|
<div class="w-full bg-gray-200 rounded-lg"> </div>
|
||||||
|
</td>
|
||||||
|
<td class="whitespace-nowrap p-3 text-sm" colspan="2">
|
||||||
|
<div class="w-full bg-gray-200 rounded-lg"> </div>
|
||||||
|
</td>
|
||||||
|
<td class="whitespace-nowrap p-3 text-sm" colspan="3">
|
||||||
|
<div class="w-full bg-gray-200 rounded-lg"> </div>
|
||||||
|
</td>
|
||||||
|
<td class="whitespace-nowrap p-3 text-sm">
|
||||||
|
<div class="w-full bg-gray-200 rounded-lg"> </div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
<div class="flex flex-col gap-8">
|
||||||
|
<div class="flex flex-col sm:grid grid-cols-8 gap-2">
|
||||||
|
<div class="relative text-sm text-gray-800 col-span-3">
|
||||||
|
<div class="absolute pl-2 left-0 top-0 bottom-0 flex items-center pointer-events-none text-gray-500">
|
||||||
|
<x-icon.magnifying-glass />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="text" placeholder="Search email or order #" class="block w-full rounded-lg border-0 py-1.5 pl-10 text-gray-900 ring-1 ring-inset ring-gray-200 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex gap-2 justify-end col-span-5">
|
||||||
|
<div class="hidden sm:flex">
|
||||||
|
<button type="button" class="flex items-center gap-2 rounded-lg border px-3 py-1.5 bg-white font-medium text-sm text-gray-700 hover:bg-gray-200">
|
||||||
|
<x-icon.arrow-down-tray />
|
||||||
|
|
||||||
|
Export
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="overflow-x-auto w-full">
|
||||||
|
<div class="relative animate-pulse min-w-[49.5rem]">
|
||||||
|
<div class="p-3">
|
||||||
|
<div class="w-full bg-gray-100 rounded-lg"> </div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="min-w-full table-fixed divide-y divide-gray-300 text-gray-800">
|
||||||
|
<tbody class="divide-y divide-gray-200 bg-white text-gray-700">
|
||||||
|
@foreach (range(0, 5) as $i)
|
||||||
|
<tr>
|
||||||
|
<td class="whitespace-nowrap p-3 text-sm">
|
||||||
|
<div class="w-full bg-gray-200 rounded-lg"> </div>
|
||||||
|
</td>
|
||||||
|
<td class="whitespace-nowrap p-3 text-sm" colspan="2">
|
||||||
|
<div class="w-full bg-gray-200 rounded-lg"> </div>
|
||||||
|
</td>
|
||||||
|
<td class="whitespace-nowrap p-3 text-sm" colspan="3">
|
||||||
|
<div class="w-full bg-gray-200 rounded-lg"> </div>
|
||||||
|
</td>
|
||||||
|
<td class="whitespace-nowrap p-3 text-sm">
|
||||||
|
<div class="w-full bg-gray-200 rounded-lg"> </div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -14,7 +14,7 @@ class="block rounded-md bg-indigo-600 px-3 py-2 text-center text-sm font-semibol
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-8 flow-root">
|
<div class="mt-8 flow-root">
|
||||||
<div class="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
<div class="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
||||||
<div class="inline-block min-w-full py-2 align-middle">
|
<div class="inline-block min-w-full py-2 align-middle mb-10">
|
||||||
<table class="min-w-full divide-y divide-gray-300">
|
<table class="min-w-full divide-y divide-gray-300">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue