firstcommit

This commit is contained in:
2025-08-17 16:23:14 +05:45
commit 76bf4c0a18
2648 changed files with 362795 additions and 0 deletions

View File

@@ -0,0 +1,131 @@
<?php
namespace Modules\Post\app\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Modules\Page\app\Models\Page;
use App\Http\Controllers\Controller;
use Illuminate\Http\RedirectResponse;
use Modules\Post\app\Http\Requests\PostRequest;
use Modules\Post\app\Repositories\PostRepository;
class PostController extends Controller
{
protected $postRepo;
public function __construct()
{
$this->postRepo = new PostRepository();
}
/**
* Display a listing of the resource.
*/
public function index(Request $request)
{
$perPage = $request->has('per-page') ? $request->input('per-page') : null;
$filter = $request->has('filter') ? $request->input('filter') : [];
$data['posts'] = $this->postRepo->findAll($perPage, $filter);
return view('post::index', $data);
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
$data['pageList'] = Page::pluck('title', 'id');
return view('post::create', $data);
}
/**
* Store a newly created resource in storage.
*/
public function store(PostRequest $request): RedirectResponse
{
try {
$validated = $request->validated();
$this->postRepo->create($validated);
toastr()->success('Data created successfully.');
return redirect()->route('post.index');
} catch (\Throwable $th) {
throw $th;
report($th);
toastr()->error('Something went wrong.');
return back();
}
}
/**
* Show the specified resource.
*/
public function show($id)
{
return view('post::show');
}
/**
* Show the form for editing the specified resource.
*/
public function edit($id)
{
$data['pageList'] = Page::pluck('title', 'id');
$data['post'] = $this->postRepo->findById($id);
if (!$data['post']) {
toastr()->success('post not found');
return back();
}
return view('post::edit', $data);
}
/**
* Update the specified resource in storage.
*/
public function update($id, PostRequest $request): RedirectResponse
{
try {
$validated = $request->validated();
$post = $this->postRepo->update($id, $validated);
if (! $post) {
toastr()->success('post not found');
return back();
}
toastr()->success('Data updated successfully.');
return redirect()->route('post.index');
} catch (\Throwable $th) {
report($th);
toastr()->error('Oops! Something went wrong.');
return redirect()->back();
}
}
/**
* Remove the specified resource from storage.
*/
public function destroy($id)
{
try {
$post = $this->postRepo->delete($id);
if (! $post) {
toastr()->error('post not found');
return back();
}
toastr()->success('Data deleted successfully.');
} catch (\Throwable $th) {
report($th);
toastr()->error('Oops! Something went wrong.');
}
return redirect()->back();
}
}

View File

View File

@@ -0,0 +1,59 @@
<?php
namespace Modules\Post\app\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class PostRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*/
public function rules(): array
{
return [
'slug' => 'nullable|string',
'image' => 'nullable|image|mimes:jpeg,png,jpg,gif',
'title' => 'nullable|string|max:255',
'short_detail' => 'nullable|string',
'full_detail' => 'nullable|string',
'page_id' => 'nullable|integer',
'order' => 'nullable|integer',
'sidebar_flag' => 'nullable|integer',
'navbar_flag' => 'nullable|integer',
'meta_title' => 'nullable',
'meta_description' => 'nullable',
'meta_keywords' => 'nullable'
];
}
public function messages()
{
return [
'slug.string' => 'The slug field must be a string.',
'image.image' => 'The image must be an image file.',
'image.mimes' => 'The image must be a file of type: jpeg, png, jpg, gif.',
'title.string' => 'The title field must be a string.',
'title.max' => 'The title may not be greater than 255 characters.',
'short_detail.string' => 'The short detail field must be a string.',
'full_detail.string' => 'The full detail field must be a string.',
'page_id.integer' => 'The page ID field must be an integer.',
'order.integer' => 'The order field must be an integer.',
];
}
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
}

View File

View File

@@ -0,0 +1,51 @@
<?php
namespace Modules\Post\app\Models;
use Modules\Page\app\Models\Page;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
const FILE_PATH = 'uploads/posts/';
/**
* The attributes that are mass assignable.
*/
protected $fillable = [
'slug',
'image',
'title',
'short_detail',
'full_detail',
'page_id',
'sidebar_flag',
'navbar_flag',
'order',
'meta_title',
'meta_description',
'meta_keywords'
];
/**
* Relation with page
*/
public function page()
{
return $this->belongsTo(Page::class, 'page_id');
}
/**
* Function to get full image path
*/
public function getFullImageAttribute()
{
$result = null;
if($this->image) {
$result = asset('storage/' . Self::FILE_PATH . $this->image);
}
return $result;
}
}

View File

View File

@@ -0,0 +1,114 @@
<?php
namespace Modules\Post\app\Providers;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
class PostServiceProvider extends ServiceProvider
{
protected string $moduleName = 'Post';
protected string $moduleNameLower = 'post';
/**
* Boot the application events.
*/
public function boot(): void
{
$this->registerCommands();
$this->registerCommandSchedules();
$this->registerTranslations();
$this->registerConfig();
$this->registerViews();
$this->loadMigrationsFrom(module_path($this->moduleName, 'database/migrations'));
}
/**
* Register the service provider.
*/
public function register(): void
{
$this->app->register(RouteServiceProvider::class);
}
/**
* Register commands in the format of Command::class
*/
protected function registerCommands(): void
{
// $this->commands([]);
}
/**
* Register command Schedules.
*/
protected function registerCommandSchedules(): void
{
// $this->app->booted(function () {
// $schedule = $this->app->make(Schedule::class);
// $schedule->command('inspire')->hourly();
// });
}
/**
* Register translations.
*/
public function registerTranslations(): void
{
$langPath = resource_path('lang/modules/'.$this->moduleNameLower);
if (is_dir($langPath)) {
$this->loadTranslationsFrom($langPath, $this->moduleNameLower);
$this->loadJsonTranslationsFrom($langPath);
} else {
$this->loadTranslationsFrom(module_path($this->moduleName, 'lang'), $this->moduleNameLower);
$this->loadJsonTranslationsFrom(module_path($this->moduleName, 'lang'));
}
}
/**
* Register config.
*/
protected function registerConfig(): void
{
$this->publishes([module_path($this->moduleName, 'config/config.php') => config_path($this->moduleNameLower.'.php')], 'config');
$this->mergeConfigFrom(module_path($this->moduleName, 'config/config.php'), $this->moduleNameLower);
}
/**
* Register views.
*/
public function registerViews(): void
{
$viewPath = resource_path('views/modules/'.$this->moduleNameLower);
$sourcePath = module_path($this->moduleName, 'resources/views');
$this->publishes([$sourcePath => $viewPath], ['views', $this->moduleNameLower.'-module-views']);
$this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->moduleNameLower);
$componentNamespace = str_replace('/', '\\', config('modules.namespace').'\\'.$this->moduleName.'\\'.config('modules.paths.generator.component-class.path'));
Blade::componentNamespace($componentNamespace, $this->moduleNameLower);
}
/**
* Get the services provided by the provider.
*/
public function provides(): array
{
return [];
}
private function getPublishableViewPaths(): array
{
$paths = [];
foreach (config('view.paths') as $path) {
if (is_dir($path.'/modules/'.$this->moduleNameLower)) {
$paths[] = $path.'/modules/'.$this->moduleNameLower;
}
}
return $paths;
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace Modules\Post\app\Providers;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class RouteServiceProvider extends ServiceProvider
{
/**
* The module namespace to assume when generating URLs to actions.
*/
protected string $moduleNamespace = 'Modules\Post\app\Http\Controllers';
/**
* Called before routes are registered.
*
* Register any model bindings or pattern based filters.
*/
public function boot(): void
{
parent::boot();
}
/**
* Define the routes for the application.
*/
public function map(): void
{
$this->mapApiRoutes();
$this->mapWebRoutes();
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*/
protected function mapWebRoutes(): void
{
Route::middleware('web')
->namespace($this->moduleNamespace)
->group(module_path('Post', '/routes/web.php'));
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*/
protected function mapApiRoutes(): void
{
Route::prefix('api')
->middleware('api')
->namespace($this->moduleNamespace)
->group(module_path('Post', '/routes/api.php'));
}
}

View File

@@ -0,0 +1,150 @@
<?php
namespace Modules\Post\app\Repositories;
use Modules\Post\app\Models\Post;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
class PostRepository
{
/**
*
*/
public function findAll($perPage=null, $filter=[], $sort=['by'=>'id', 'sort'=>'DESC'])
{
return Post::when(array_keys($filter, true), function ($query) use ($filter) {
if (!empty($filter['page_id'])) {
$query->where('page_id', $filter['page_id']);
}
})
->orderBy($sort['by'], $sort['sort'])
->paginate($perPage ?: env('PAGE_LIMIT', 999));
}
/**
*
*/
public function findBySlug($slug)
{
return Post::where('slug', $slug)->first();
}
/**
*
*/
public function findById($id)
{
return Post::where('id', $id)->first();
}
/**
*
*/
public function create(array $data)
{
$result = false;
DB::beginTransaction();
try {
if(isset($data['image'])) {
$data['image'] = $this->upload($data['image']);
}
$result = Post::create($data);
if($result) {
DB::commit();
}
} catch (\Throwable $th) {
report($th);
DB::rollback();
}
return $result;
}
/**
*
*/
public function update($id, array $data)
{
$result = false;
DB::beginTransaction();
try {
$model = $this->findById($id);
$oldImage = $model->image;
if(isset($data['image'])) {
if (!is_null($oldImage)) {
$this->remove($oldImage);
}
$data['image'] = $this->upload($data['image']);
}
$result = $model->update($data);
if($result) {
DB::commit();
}
} catch (\Throwable $th) {
report($th);
DB::rollback();
}
return $result;
}
/**
*
*/
public function delete($id)
{
$result = false;
DB::beginTransaction();
try {
$model = $this->findById($id);
$oldImage = $model->image;
$result = $model->delete();
if($result) {
$this->remove($oldImage);
DB::commit();
}
} catch (\Throwable $th) {
report($th);
DB::rollback();
}
return $result;
}
/**
*
*/
public function upload($file)
{
$fileExtension = $file->getClientOriginalExtension();
$fileName = 'IMG' . time() . '.' . $fileExtension;
$file->move(storage_path() . '/app/public/' . Post::FILE_PATH, $fileName);
return $fileName;
}
/**
*
*/
public function remove($fileName)
{
$fullFilePath = storage_path() . '/app/public/' . Post::FILE_PATH . $fileName;
if (file_exists($fullFilePath)) {
unlink($fullFilePath);
}
return true;
}
}

View File

@@ -0,0 +1,31 @@
{
"name": "nwidart/post",
"description": "",
"authors": [
{
"name": "Nicolas Widart",
"email": "n.widart@gmail.com"
}
],
"extra": {
"laravel": {
"providers": [],
"aliases": {
}
}
},
"autoload": {
"psr-4": {
"Modules\\Post\\": "",
"Modules\\Post\\App\\": "app/",
"Modules\\Post\\Database\\Factories\\": "database/factories/",
"Modules\\Post\\Database\\Seeders\\": "database/seeders/"
}
},
"autoload-dev": {
"psr-4": {
"Modules\\Post\\Tests\\": "tests/"
}
}
}

View File

View File

@@ -0,0 +1,5 @@
<?php
return [
'name' => 'Post',
];

View File

View File

@@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('slug')->nullable();
$table->string('image')->nullable();
$table->string('title')->nullable();
$table->text('short_detail')->nullable();
$table->longText('full_detail')->nullable();
$table->integer('page_id')->nullable();
$table->integer('order')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('posts');
}
};

View File

@@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('posts', function (Blueprint $table) {
$table->integer('sidebar_flag')->default(11)->after('page_id');
$table->integer('navbar_flag')->default(11)->after('sidebar_flag');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('posts', function (Blueprint $table) {
$table->dropColumn('sidebar_flag');
$table->dropColumn('navbar_flag');
});
}
};

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('posts', function (Blueprint $table) {
$table->string('meta_title')->nullable();
$table->string('meta_description')->nullable();
$table->string('meta_keywords')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('posts', function (Blueprint $table) {
$table->dropColumn('meta_title');
$table->dropColumn('meta_description');
$table->dropColumn('meta_keywords');
});
}
};

View File

View File

@@ -0,0 +1,93 @@
<?php
namespace Modules\Post\database\seeders;
use Illuminate\Support\Str;
use Illuminate\Database\Seeder;
use Modules\Page\app\Models\Page;
use Modules\Post\app\Models\Post;
use Illuminate\Support\Facades\Storage;
class PostDatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$datas = array(
[
'slug' => 'mission',
'image' => null,
'title' => 'Mission',
'short_detail' => null,
'full_detail' => '<p>Arogin Health Care and Research Center aims to foster lives of million through quality health care and services. We not just sell promises but strive to deliver it. Cost-effective and accessible services, use of cutting-edge technologies, and commitment of highly skilled staffs provide an environment of affordable solace. Here, at Arogin Health Care and Research Centre, we maintain a healthy and friendly work environment where each one is motivated to deliver their best. Our team plan on making healthy benefits through clients&rsquo; satisfaction.</p>',
'page_id' => 2,
'order' => 1,
],
[
'slug' => 'vision',
'image' => null,
'title' => 'Vision',
'short_detail' => null,
'full_detail' => '<p>At Arogin Health Care and Research Centre, we dream to see beyond the ordinary to explore the best of what we can. We envision patient-focused health care services where we aim to respond to needs of people through quality care. By providing sophisticated yet cost-effective services we tend to attract foreign costumers and also provide services of international standard locally. With teams of proficient staffs we aim on making it a professional hub of excellence.</p>',
'page_id' => 2,
'order' => 2,
],
[
'slug' => 'specialization',
'image' => null,
'title' => 'Specialization',
'short_detail' => null,
'full_detail' => '<p>We aim to introduce the best quality hair transplantation service here in Nepal. We provide preeminent hair transplantation services with the team lead by adept professional. We don&rsquo;t impose our services rather we suggest them the best possibilities where they are free to decide what they want. Furthermore, in collaboration with Nabil Bank we have also offered installment plans to make the service more affordable and convenient.</p>',
'page_id' => 2,
'order' => 3,
],
[
'slug' => 'direct-hair-transplant',
'image' => null,
'title' => 'Direct Hair Transplant (DHT)',
'short_detail' => null,
'full_detail' => "<p>Hair loss is a common concern that affects millions of people worldwide, regardless of age or gender. It can have a significant impact on an individual's self-esteem, confidence, and overall quality of life. Over the years, various hair restoration techniques have been developed to combat this issue. And one such groundbreaking approach is&nbsp;<strong>Direct Hair Transplant (DHT)</strong>. DHT represents a modern leap forward in hair transplantation, providing patients with natural-looking and long-lasting results.</p>
<p>&nbsp;</p>
<h3>Understanding Direct Hair Transplant (DHT):</h3>
<p>DHT is a modified version of the traditional&nbsp;<strong>Follicular Unit Extraction (FUE) method</strong>, which has gained popularity for its minimally invasive nature and ability to harvest individual hair follicles from the donor area without leaving a linear scar. However, DHT takes the FUE procedure to a new level by making the transplantation process more efficient and effective.</p>
<p>&nbsp;</p>
<p>In conventional FUE, after the hair follicles are extracted from the donor area, they are sorted, counted, and stored outside the body while the recipient area is being prepared for transplantation. This waiting period, although relatively short, can still impact the viability of the hair follicles. The follicles may become dehydrated or damaged during this time, potentially leading to lower survival rates and decreased success of the transplantation.</p>",
'page_id' => 3,
'order' => 1,
],
[
'slug' => 'painless-hair-transplantation',
'image' => null,
'title' => 'Painless Hair Transplantation',
'short_detail' => null,
'full_detail' => '<p>Hair transplantation is a cosmetic procedure which involves the extraction of hair roots from the donor area (back and sides of the scalp) and planting it to the recipient area i.e. bald area. Hair can also be taken from beard, chest, axilla and other body parts.</p>
<p>&nbsp;</p>
<p>The basic concept of hair transplantation is based on the principle of &lsquo;donor dominance&rsquo;. Donor dominance implies that transplanted hair will retain its properties of original site even when moved to a bald area. We know that in pattern hair loss ( Androgenetic alopecia), the area in the front, middle and crown part of the scalp is susceptible to DHT where as back and sides are not. Hair transplantation this follows the concept of transferring DHT immune hairs to the bald areas.</p>
<p>&nbsp;</p>
<h3>ALOPECIA AREATA</h3>
<p>Alopecia areata is the conditions for hair fall in which person&rsquo;s immune system attack his/her own hair follicles causing hair loss. It presents as smooth circular to oval patches of hair loss over scalp, beard, eyebrows or any other body sites.</p>
<p>&nbsp;</p>
<h3>ANDROGENETIC ALOPECIA (PATTERN HAIR LOSS)</h3>
<p>Androgenetic alopecia also called a pattern hair loss is the most common cause of hair loss in which thick hairs gradually become thin and short because of the byproduct Dihydrotestosterone (DHT) of male hormone testosterone.</p>
<p>&nbsp;</p>
<p>It is also called a pattern hair loss because hair loss follows a particular pattern. Male tends to lose hair in the front, crown and middle part of scalp but retain hair at the sides and back of the scalp. These retained hairs has the DHT resistant follicles, are often referred to as the &ldquo;permanent zone&rdquo;.</p>',
'page_id' => 3,
'order' => 2,
]
);
foreach ($datas as $data) {
Post::create([
'slug' => $data['slug'],
'image' => $data['image'],
'title' => $data['title'],
'short_detail' => $data['short_detail'],
'full_detail' => $data['full_detail'],
'page_id' => $data['page_id'],
'order' => $data['order']
]);
}
}
}

View File

11
Modules/Post/module.json Normal file
View File

@@ -0,0 +1,11 @@
{
"name": "Post",
"alias": "post",
"description": "",
"keywords": [],
"priority": 0,
"providers": [
"Modules\\Post\\app\\Providers\\PostServiceProvider"
],
"files": []
}

15
Modules/Post/package.json Normal file
View File

@@ -0,0 +1,15 @@
{
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build"
},
"devDependencies": {
"axios": "^1.1.2",
"laravel-vite-plugin": "^0.7.5",
"sass": "^1.69.5",
"postcss": "^8.3.7",
"vite": "^4.0.0"
}
}

View File

View File

View File

View File

@@ -0,0 +1,38 @@
@extends('admin::layouts.master')
@section('title')
Create Post
@endsection
@section('breadcrumb')
@php
$breadcrumbData = [
[
'title' => 'Create',
'link' => 'null',
],
[
'title' => 'Dashboard',
'link' => route('dashboard'),
],
[
'title' => 'Posts',
'link' => route('post.index'),
],
[
'title' => 'Create',
'link' => null,
],
];
@endphp
@include('admin::layouts.partials.breadcrumb', $breadcrumbData)
@endsection
@section('content')
<form action="{{ route('post.store') }}" method="POST" enctype="multipart/form-data">
@csrf
@include('post::partial.form')
</form>
@endsection

View File

@@ -0,0 +1,39 @@
@extends('admin::layouts.master')
@section('title')
Update Post
@endsection
@section('breadcrumb')
@php
$breadcrumbData = [
[
'title' => 'Post',
'link' => 'null',
],
[
'title' => 'Dashboard',
'link' => route('dashboard'),
],
[
'title' => 'Posts',
'link' => route('post.index'),
],
[
'title' => 'Update',
'link' => null,
],
];
@endphp
@include('admin::layouts.partials.breadcrumb', $breadcrumbData)
@endsection
@section('content')
<form action="{{ route('post.update', ['id' => $post->id]) }}" method="POST" enctype="multipart/form-data">
@csrf
@method('put')
@include('post::partial.form', $post)
</form>
@endsection

View File

@@ -0,0 +1,111 @@
@extends('admin::layouts.master')
@section('title')
Posts
@endsection
@section('breadcrumb')
@php
$breadcrumbData = [
[
'title' => 'Posts',
'link' => 'null',
],
[
'title' => 'Dashboard',
'link' => route('dashboard'),
],
[
'title' => 'Posts',
'link' => null,
],
];
@endphp
@include('admin::layouts.partials.breadcrumb', $breadcrumbData)
@endsection
@section('content')
<div class="card">
<div class="row">
<div class="col-md-6">
<h4 class="card-header">List of Post</h4>
</div>
<div class="col-md-6">
<div class="flex-column flex-md-row">
<div class="dt-action-buttons text-end pt-3 px-3">
<div class="dt-buttons btn-group flex-wrap">
<a href="{{ route('post.create') }}"
class="btn btn-secondary create-new btn-primary d-none d-sm-inline-block text-white">
<i class="bx bx-plus me-sm-1"></i>
Add New
</a>
</div>
</div>
</div>
</div>
</div>
<div class="card-datatable table-responsive">
<table class="datatables-users table table-hover border-top">
<thead class="table-light">
<tr>
<th>S.N</th>
<th>Title With Image</th>
<th>Page</th>
<th>Actions</th>
</tr>
</thead>
<tbody class="table-border-bottom-0">
@foreach ($posts ?? [] as $post)
<tr>
<td>
#{{ $loop->iteration }}
</td>
<td>
<div class="d-flex align-items-center me-3">
<img src="{{ asset($post->fullImage ?? 'backend/uploads/images/no-Image.jpg') }}" alt="Image" class="rounded me-3" height="40" width="60" style="object-fit: cover">
<div class="card-title mb-0">
<h6 class="mb-0">{{ $post->title }}</h6>
<small class="text-muted">{{ Str::limit($post->short_detail, 80) }}</small>
</div>
</div>
</td>
<td>
{{ optional($post->page)->title }}
</td>
<td>
<div class="dropdown">
<button type="button" class="btn p-0 dropdown-toggle hide-arrow"
data-bs-toggle="dropdown">
<i class="bx bx-dots-vertical-rounded"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item"
href="{{ route('post.edit', ['id' => $post->id]) }}"><i
class="bx bx-edit-alt me-1"></i>
Edit</a>
<form method="POST"
action="{{ route('post.delete', ['id' => $post->id]) }}"
id="deleteForm_{{ $post->id }}" class="dropdown-item">
@csrf
@method('DELETE')
<button type="submit" class="border-0 bg-transparent deleteBtn"
style="color:inherit"><i class="bx bx-trash me-1"></i> Delete</button>
</form>
</div>
</div>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="px-3">
{{ $posts->links('admin::layouts.partials.pagination') }}
</div>
</div>
@endsection

View File

@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Post Module - {{ config('app.name', 'Laravel') }}</title>
<meta name="description" content="{{ $description ?? '' }}">
<meta name="keywords" content="{{ $keywords ?? '' }}">
<meta name="author" content="{{ $author ?? '' }}">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
{{-- Vite CSS --}}
{{-- {{ module_vite('build-post', 'resources/assets/sass/app.scss') }} --}}
</head>
<body>
@yield('content')
{{-- Vite JS --}}
{{-- {{ module_vite('build-post', 'resources/assets/js/app.js') }} --}}
</body>

View File

@@ -0,0 +1,158 @@
@push('required-styles')
@include('admin::vendor.select2.style')
@endpush
<div class="row">
<div class="col-md-8">
<div class="card">
<div class="card-body">
<div class="row" x-data="generateSlug()" x-init="title = '{{ addslashes(old('title', $post->title ?? '')) }}';
slug = '{{ addslashes(old('slug', $post->slug ?? '')) }}'">
<div class="col-12">
<h6 class="fw-normal">1. Basic Details</h6>
<hr class="mt-0">
</div>
<div class="col-md-12" x-data="generateSlug()">
{{-- <div class="d-flex align-items-start align-items-sm-center gap-4">
<img src="{{ isset($post->image) ? $post->fullImage : asset('backend/uploads/images/no-Image.jpg') }}"
alt="destination-image input-file" class="d-block rounded show-image" height="100"
width="100" />
<div class="button-wrapper">
<label for="upload" class="btn btn-primary btn-sm me-2 mb-4" tabindex="0">
<span class="d-none d-sm-block">Upload</span>
<i class="bx bx-upload d-block d-sm-none"></i>
<input type="file" id="upload" class="input-file" name="image" hidden
accept="image/png, image/jpeg" />
</label>
<button type="button" class="btn btn-label-secondary btn-sm image-reset mb-4">
<i class="bx bx-reset d-block d-sm-none"></i>
<span class="d-none d-sm-block">Reset</span>
</button>
<p class="mb-0">Allowed JPG, GIF or PNG. Max size of 3Mb</p>
</div>
</div>
<hr class="mt-2" /> --}}
</div>
<div class="col-md-6 mb-3">
<label class="form-label">Title <span class="text-danger">*</span></label>
<input type="text" class="form-control" x-model="title" x-on:input="updateSlug()" name="title"
value="{{ old('title', $post->title ?? '') }}" placeholder="e.g. Hair Transplant" required />
@error('title')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<div class="col-md-6 mb-3">
<label class="form-label">Slug <span class="text-danger">*</span></label>
<input type="text" class="form-control" x-model="slug" name="slug"
value="{{ old('slug', $post->slug ?? '') }}" placeholder="e.g. hair-transplant" required />
@error('slug')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<div class="col-md-12 mb-3">
<label class="form-label">Short Detail</label>
<textarea class="form-control" rows="3" name="short_detail" placeholder="Short detail..">{{ old('short_detail', $post->short_detail ?? '') }}</textarea>
@error('short_detail')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<div class="col-md-12 mb-3">
<label class="form-label">Full Detail</label>
<textarea class="form-control" rows="7" id="advance" name="full_detail" placeholder="Full details..">{!! old('full_detail', $post->full_detail ?? '') !!}</textarea>
@error('full_detail')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<div class="col-md-12">
<button type="submit" class="btn btn-primary">
@if (empty($post))
Save
@else
Save Changes
@endif
</button>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card mb-4">
<h5 class="card-header">Additional Details</h5>
<div class="card-body">
<div class="col-md-12 mb-3">
<label class="form-label">Page</label>
<select id="select2Basic" class="select2 form-select" name="page_id" data-allow-clear="true">
<option value=""></option>
@foreach ($pageList ?? [] as $pageId => $pageTitle)
<option value="{{ $pageId }}" {{ ($post->page_id ?? '') == $pageId ? 'selected' : '' }}>
{{ $pageTitle }}
</option>
@endforeach
</select>
@error('page_id')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<div class="col-md-12 mb-3">
<label class="form-label">Order</label>
<input class="form-control" type="number" name="order"
value="{{ old('order', $post->order ?? '') }}" placeholder="e.g. 1" />
@error('order')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<div class="mb-3 col-md-12">
<label for="sidebarFlag" class="form-label">Show on Sidebar</label>
<div class="position-relative">
<select id="sidebarFlag select2Basic" class="select2 form-select select2-hidden-accessible"
data-select2-id="sidebarFlag" tabindex="-1" aria-hidden="true" name="sidebar_flag">
<option value="11"
{{ old('sidebar_flag', $post->sidebar_flag ?? '') == '11' ? 'selected' : '' }}>Yes
</option>
<option value="10"
{{ old('sidebar_flag', $post->sidebar_flag ?? '') == '10' ? 'selected' : '' }}>No
</option>
</select>
</div>
</div>
<div class="mb-3 col-md-12">
<label for="language" class="form-label">Show on Navbar</label>
<div class="position-relative">
<select id="language select2Basic" class="select2 form-select select2-hidden-accessible"
data-select2-id="language" tabindex="-1" aria-hidden="true" name="navbar_flag">
<option value="11"
{{ old('navbar_flag', $post->navbar_flag ?? '') == '11' ? 'selected' : '' }}>Yes
</option>
<option value="10"
{{ old('navbar_flag', $post->navbar_flag ?? '') == '10' ? 'selected' : '' }}>No
</option>
</select>
</div>
</div>
</div>
</div>
<div class="card mb-4">
<h5 class="card-header">Meta Details</h5>
<div class="card-body">
<div class="mb-3 col-md-12">
<label for="exampleFormControlTextarea1" class="form-label">Meta Title</label>
<textarea class="form-control" id="exampleFormControlTextarea1" rows="3" name="meta_title" placeholder="Title..">{{ old('meta_title', $post->meta_title ?? '') }}</textarea>
</div>
<div class="mb-3 col-md-12">
<label for="exampleFormControlTextarea1" class="form-label">Meta Description</label>
<textarea class="form-control" id="exampleFormControlTextarea1" rows="3" name="meta_description" placeholder="Description..">{{ old('meta_description', $post->meta_description ?? '') }}</textarea>
</div>
<div class="mb-3 col-md-12">
<label for="exampleFormControlTextarea1" class="form-label">Meta Keywords</label>
<textarea class="form-control" id="exampleFormControlTextarea1" rows="3" name="meta_keywords" placeholder="Keywords..">{{ old('meta_keywords', $post->meta_keywords ?? '') }}</textarea>
</div>
</div>
</div>
</div>
</div>
@push('required-scripts')
@include('admin::vendor.select2.script')
@include('admin::vendor.tinymce.script')
@endpush

View File

View File

@@ -0,0 +1,19 @@
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::middleware(['auth:sanctum'])->prefix('v1')->name('api.')->group(function () {
Route::get('post', fn (Request $request) => $request->user())->name('post');
});

View File

@@ -0,0 +1,24 @@
<?php
use Illuminate\Support\Facades\Route;
use Modules\Post\app\Http\Controllers\PostController;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::group(['prefix' => 'apanel', 'middleware' => ['auth']], function () {
Route::get('posts', [PostController::class, 'index'])->name('post.index');
Route::get('posts/create', [PostController::class, 'create'])->name('post.create');
Route::post('posts/store', [PostController::class, 'store'])->name('post.store');
Route::get('posts/{id}/edit', [PostController::class, 'edit'])->name('post.edit');
Route::put('posts/{id}/update', [PostController::class, 'update'])->name('post.update');
Route::delete('posts/{id}/delete', [PostController::class, 'destroy'])->name('post.delete');
});

View File

View File

View File

@@ -0,0 +1,26 @@
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
export default defineConfig({
build: {
outDir: '../../public/build-post',
emptyOutDir: true,
manifest: true,
},
plugins: [
laravel({
publicDirectory: '../../public',
buildDirectory: 'build-post',
input: [
__dirname + '/resources/assets/sass/app.scss',
__dirname + '/resources/assets/js/app.js'
],
refresh: true,
}),
],
});
//export const paths = [
// 'Modules/$STUDLY_NAME$/resources/assets/sass/app.scss',
// 'Modules/$STUDLY_NAME$/resources/assets/js/app.js',
//];