Add (v1)
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Post;
|
||||
use App\Models\PostCategory;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class PostController extends Controller
|
||||
@@ -27,10 +28,113 @@ public function edit(Request $request, $post_id)
|
||||
{
|
||||
$post = Post::find($post_id);
|
||||
|
||||
if (!is_null($post))
|
||||
{
|
||||
if (! is_null($post)) {
|
||||
return view('admin.posts.upsert', compact('post'));
|
||||
}
|
||||
return redirect()->back()->with('error','Post does not exist.');
|
||||
|
||||
return redirect()->back()->with('error', 'Post does not exist.');
|
||||
}
|
||||
|
||||
public function postUpsert(Request $request)
|
||||
{
|
||||
|
||||
$post_data = [
|
||||
'id' => $request->input('id', null),
|
||||
'publish_date' => $request->input('publish_date', null),
|
||||
'title' => $request->input('title'),
|
||||
'slug' => $request->input('slug'),
|
||||
'excerpt' => $request->input('excerpt'),
|
||||
'author_id' => intval($request->input('author_id', 1)),
|
||||
'featured' => filter_var($request->input('featured'), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE),
|
||||
'featured_image' => $request->input('featured_image'),
|
||||
'editor' => 'editorjs',
|
||||
'body' => json_decode($request->input('body')),
|
||||
'post_format' => 'standard',
|
||||
'comment_count' => 0,
|
||||
'likes_count' => 0,
|
||||
'status' => $request->input('status'),
|
||||
];
|
||||
|
||||
$post_categories = $this->normalizeCategories($request->input('categories'));
|
||||
|
||||
if (! empty($post_data['id'])) {
|
||||
// It's an update - find the existing post by its ID
|
||||
$existingPost = Post::find($post_data['id']);
|
||||
|
||||
// Check if the post with the given ID exists
|
||||
if ($existingPost) {
|
||||
// Update the existing post with the new data
|
||||
$existingPost->update($post_data);
|
||||
|
||||
// Handle PostCategory records for the existing post
|
||||
$existingPostCategoryIds = $existingPost?->post_categories->pluck('id')->toArray();
|
||||
|
||||
// Find the IDs of PostCategory records that should be removed
|
||||
$postCategoriesToRemove = array_diff($existingPostCategoryIds, $post_categories);
|
||||
|
||||
// Remove the unwanted PostCategory records
|
||||
if (! empty($postCategoriesToRemove)) {
|
||||
PostCategory::whereIn('id', $postCategoriesToRemove)->delete();
|
||||
}
|
||||
|
||||
// Find the new PostCategory records that should be added
|
||||
$postCategoriesToAdd = array_diff($post_categories, $existingPostCategoryIds);
|
||||
|
||||
// Create the new PostCategory records
|
||||
foreach ($postCategoriesToAdd as $categoryId) {
|
||||
PostCategory::create([
|
||||
'post_id' => $existingPost->id,
|
||||
'category_id' => $categoryId,
|
||||
]);
|
||||
}
|
||||
|
||||
// Return a response indicating a successful update
|
||||
return response()->json(['message' => 'Post updated successfully', 'action' => 'redirect_back']);
|
||||
} else {
|
||||
// If the post with the given ID doesn't exist, you can handle the error as per your requirement
|
||||
return response()->json(['error' => 'Post not found'], 404);
|
||||
}
|
||||
} else {
|
||||
// It's a new post - create a new record using Post::create
|
||||
$newPost = Post::create($post_data);
|
||||
|
||||
// Create the new PostCategory records for the new post
|
||||
foreach ($post_categories as $categoryId) {
|
||||
PostCategory::create([
|
||||
'post_id' => $newPost->id,
|
||||
'category_id' => $categoryId,
|
||||
]);
|
||||
}
|
||||
|
||||
// Return a response indicating a successful creation
|
||||
return response()->json(['message' => 'Post created successfully', 'action' => 'redirect_back']);
|
||||
}
|
||||
}
|
||||
|
||||
private function normalizeCategories($categories)
|
||||
{
|
||||
if (empty($categories) || is_null($categories)) {
|
||||
// If the input is empty or null, return an empty array
|
||||
return [];
|
||||
} elseif (is_numeric($categories)) {
|
||||
// If the input is a numeric value (integer or string), return an array with the integer value
|
||||
return [(int) $categories];
|
||||
} else {
|
||||
// If the input is a string with separated commas or a JSON string that becomes an array of integers, return an array of integers
|
||||
if (is_string($categories)) {
|
||||
// Attempt to convert the string to an array of integers
|
||||
$categoryIds = json_decode($categories, true);
|
||||
|
||||
// Check if the decoding was successful and the result is an array of integers
|
||||
if (is_array($categoryIds) && ! empty($categoryIds)) {
|
||||
$categoryIds = array_map('intval', $categoryIds);
|
||||
|
||||
return $categoryIds;
|
||||
}
|
||||
}
|
||||
|
||||
// If the input format doesn't match any of the above cases, return an empty array
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,25 @@
|
||||
use App\Models\Post;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
use Artesaos\SEOTools\Facades\SEOTools;
|
||||
use Artesaos\SEOTools\Facades\SEOMeta;
|
||||
use Artesaos\SEOTools\Facades\OpenGraph;
|
||||
use Artesaos\SEOTools\Facades\JsonLd;
|
||||
use Artesaos\SEOTools\Facades\JsonLdMulti;
|
||||
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
|
||||
SEOTools::metatags();
|
||||
SEOTools::twitter();
|
||||
SEOTools::opengraph();
|
||||
SEOTools::jsonLd();
|
||||
SEOTools::setTitle("Top Product Reviews, Deals & New Launches");
|
||||
SEOTools::setDescription("Explore ProductAlert for in-depth product reviews and incredible deals. We cover Beauty, Tech, Home Appliances, Health & Fitness, Parenting, and more.");
|
||||
|
||||
$country = strtolower($request->session()->get('country'));
|
||||
|
||||
return redirect()->route('home.country', ['country' => $country]);
|
||||
@@ -19,6 +34,8 @@ public function index(Request $request)
|
||||
|
||||
public function country(Request $request, $country)
|
||||
{
|
||||
|
||||
|
||||
$country_locale = CountryLocale::where('slug', $country)->first();
|
||||
|
||||
if (! is_null($country_locale)) {
|
||||
@@ -50,6 +67,17 @@ public function country(Request $request, $country)
|
||||
->take(10)
|
||||
->get();
|
||||
|
||||
|
||||
SEOTools::metatags();
|
||||
SEOTools::twitter();
|
||||
SEOTools::opengraph();
|
||||
SEOTools::jsonLd();
|
||||
|
||||
$country_name = get_country_name_by_iso($country_locale->country_iso);
|
||||
|
||||
SEOTools::setTitle("Your {$country_name} Guide to Product Reviews & Top Deals");
|
||||
SEOTools::setDescription("Discover trusted product reviews and unbeatable deals at ProductAlert {$country_name}, your local guide to smart shopping.");
|
||||
|
||||
return view('front.country', compact('country_locale', 'featured_posts', 'latest_posts')
|
||||
);
|
||||
}
|
||||
@@ -83,6 +111,20 @@ public function countryCategory(Request $request, $country, $category)
|
||||
->distinct()
|
||||
->paginate(15);
|
||||
|
||||
SEOTools::metatags();
|
||||
SEOTools::twitter();
|
||||
SEOTools::opengraph();
|
||||
SEOTools::jsonLd();
|
||||
|
||||
$country_name = get_country_name_by_iso($country_locale->country_iso);
|
||||
|
||||
SEOTools::setTitle("Top {$category->name} Reviews in {$country_name}");
|
||||
|
||||
$category_name = strtolower($category->name);
|
||||
|
||||
SEOTools::setDescription("Stay updated with the latest {$category_name} product launches in {$country_name}. Find in-depth reviews and exciting deals with ProductAlert, your guide to {$category_name} shopping.");
|
||||
|
||||
|
||||
return view('front.country_category', compact('country_locale', 'category', 'latest_posts'));
|
||||
}
|
||||
|
||||
@@ -101,6 +143,17 @@ public function all(Request $request, $country)
|
||||
->distinct()
|
||||
->paginate(15);
|
||||
|
||||
SEOTools::metatags();
|
||||
SEOTools::twitter();
|
||||
SEOTools::opengraph();
|
||||
SEOTools::jsonLd();
|
||||
|
||||
$country_name = get_country_name_by_iso($country_locale->country_iso);
|
||||
|
||||
SEOTools::setTitle("Find Product Reviews and Best Deals for {$country_name}");
|
||||
|
||||
SEOTools::setDescription("Discover the latest product reviews and unbeatable deals at ProductAlert, your guide to shopping in {$country_name}. Stay on top of fresh product updates.");
|
||||
|
||||
return view('front.country_all', compact('country_locale', 'latest_posts'));
|
||||
}
|
||||
|
||||
@@ -110,6 +163,32 @@ public function post(Request $request, $country, $post_slug)
|
||||
|
||||
if (! is_null($post)) {
|
||||
|
||||
|
||||
SEOMeta::setTitle($post->title);
|
||||
SEOMeta::setDescription($post->excerpt);
|
||||
SEOMeta::addMeta('article:published_time', $post->publish_date, 'property');
|
||||
SEOMeta::addMeta('article:section', $post->post_category->category->name, 'property');
|
||||
|
||||
OpenGraph::setDescription($post->excerpt);
|
||||
OpenGraph::setTitle($post->title);
|
||||
OpenGraph::setUrl(url()->current());
|
||||
OpenGraph::addProperty('type', 'article');
|
||||
OpenGraph::addProperty('locale', $post->post_category->category->country_locale->i18n);
|
||||
OpenGraph::addImage($post->featured_image);
|
||||
|
||||
$jsonld_multi = JsonLdMulti::newJsonLd();
|
||||
$jsonld_multi->setTitle($post->title)
|
||||
->setDescription($post->excerpt)
|
||||
->setType('Article')
|
||||
->addImage($post->featured_image)
|
||||
->addValue('author', $post->author->name)
|
||||
->addValue('datePublished', $post->publish_at)
|
||||
->addValue('dateCreated', $post->publish_at)
|
||||
->addValue('dateModified', $post->updated_at->format('Y-m-d'))
|
||||
->addValue('description', $post->excerpt)
|
||||
->addValue('articleBody', trim(preg_replace('/\s\s+/', ' ', strip_tags($post->html_body))))
|
||||
;
|
||||
|
||||
return view('front.post', compact('post'));
|
||||
}
|
||||
abort(404);
|
||||
|
||||
@@ -4,13 +4,9 @@
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Intervention\Image\Facades\Image;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
use Intervention\Image\Facades\Image;
|
||||
|
||||
class ImageUploadController extends Controller
|
||||
{
|
||||
@@ -26,8 +22,8 @@ public function index(Request $request)
|
||||
|
||||
// Generate a unique filename for the uploaded file and LQIP version
|
||||
$uuid = Str::uuid()->toString();
|
||||
$fileName = time() . '_' . $uuid . '.jpg';
|
||||
$lqipFileName = time() . '_' . $uuid . '_lqip.jpg';
|
||||
$fileName = time().'_'.$uuid.'.jpg';
|
||||
$lqipFileName = time().'_'.$uuid.'_lqip.jpg';
|
||||
|
||||
// Convert the file to JPEG format using Intervention Image library
|
||||
$image = Image::make($file->getRealPath())->encode('jpg', 100);
|
||||
@@ -46,8 +42,8 @@ public function index(Request $request)
|
||||
$image->encode('jpg', 50);
|
||||
|
||||
// Save the processed image to the 'r2' storage driver under the 'uploads' directory
|
||||
$filePath = 'uploads/' . $fileName;
|
||||
$lqipFilePath = 'uploads/' . $lqipFileName;
|
||||
$filePath = 'uploads/'.$fileName;
|
||||
$lqipFilePath = 'uploads/'.$lqipFileName;
|
||||
Storage::disk('r2')->put($filePath, $image->stream()->detach());
|
||||
|
||||
// Save the original image to a temporary file and open it again
|
||||
@@ -56,7 +52,7 @@ public function index(Request $request)
|
||||
$clonedImage = Image::make($tempImagePath);
|
||||
|
||||
// Create the LQIP version of the image using a small size while maintaining the aspect ratio
|
||||
$lqipImage = $clonedImage->fit(10, 10, function ($constraint) use ($originalWidth, $originalHeight) {
|
||||
$lqipImage = $clonedImage->fit(10, 10, function ($constraint) {
|
||||
$constraint->aspectRatio();
|
||||
});
|
||||
$lqipImage->encode('jpg', 5);
|
||||
|
||||
@@ -40,6 +40,7 @@ class Post extends Model
|
||||
'body' => 'json',
|
||||
'comment_count' => 'int',
|
||||
'likes_count' => 'int',
|
||||
'featured' => 'bool',
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
@@ -54,10 +55,12 @@ class Post extends Model
|
||||
'comment_count',
|
||||
'likes_count',
|
||||
'status',
|
||||
'featured',
|
||||
'publish_date',
|
||||
];
|
||||
|
||||
protected $appends = [
|
||||
'html_body',
|
||||
//'html_body',
|
||||
];
|
||||
|
||||
public function author()
|
||||
@@ -78,7 +81,7 @@ public function post_category()
|
||||
public function getHtmlBodyAttribute()
|
||||
{
|
||||
if (! is_empty($this->body)) {
|
||||
return LaravelEditorJs::render($this->body);
|
||||
return LaravelEditorJs::render(json_encode($this->body));
|
||||
}
|
||||
|
||||
return '';
|
||||
|
||||
@@ -161,6 +161,7 @@
|
||||
*/
|
||||
Barryvdh\Debugbar\ServiceProvider::class,
|
||||
Stevebauman\Location\LocationServiceProvider::class,
|
||||
Artesaos\SEOTools\Providers\SEOToolsServiceProvider::class,
|
||||
|
||||
/*
|
||||
* Application Service Providers...
|
||||
@@ -187,6 +188,12 @@
|
||||
'aliases' => Facade::defaultAliases()->merge([
|
||||
// 'Example' => App\Facades\Example::class,
|
||||
'Debugbar' => Barryvdh\Debugbar\Facades\Debugbar::class,
|
||||
'SEOMeta' => Artesaos\SEOTools\Facades\SEOMeta::class,
|
||||
'OpenGraph' => Artesaos\SEOTools\Facades\OpenGraph::class,
|
||||
'Twitter' => Artesaos\SEOTools\Facades\TwitterCard::class,
|
||||
'JsonLd' => Artesaos\SEOTools\Facades\JsonLd::class,
|
||||
'JsonLdMulti' => Artesaos\SEOTools\Facades\JsonLdMulti::class,
|
||||
'SEO' => Artesaos\SEOTools\Facades\SEOTools::class,
|
||||
|
||||
])->toArray(),
|
||||
|
||||
|
||||
@@ -69,7 +69,6 @@
|
||||
'throw' => true,
|
||||
],
|
||||
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
* The default configurations to be used by the meta generator.
|
||||
*/
|
||||
'defaults' => [
|
||||
'title' => "It's Over 9000!", // set false to total remove
|
||||
'title' => "ProductAlert", // set false to total remove
|
||||
'titleBefore' => false, // Put defaults.title before page title, like 'It's Over 9000! - Dashboard'
|
||||
'description' => 'For those who helped create the Genki Dama', // set false to total remove
|
||||
'description' => 'Find top-rated product reviews at ProductAlert. Discover the latest trends, best brands, and right prices. Your guide to making the best purchase decisions!', // set false to total remove
|
||||
'separator' => ' - ',
|
||||
'keywords' => [],
|
||||
'canonical' => false, // Set to null or 'full' to use Url::full(), set to 'current' to use Url::current(), set false to total remove
|
||||
@@ -36,8 +36,8 @@
|
||||
* The default configurations to be used by the opengraph generator.
|
||||
*/
|
||||
'defaults' => [
|
||||
'title' => 'Over 9000 Thousand!', // set false to total remove
|
||||
'description' => 'For those who helped create the Genki Dama', // set false to total remove
|
||||
'title' => 'ProductAlert', // set false to total remove
|
||||
'description' => 'Find top-rated product reviews at ProductAlert. Discover the latest trends, best brands, and right prices. Your guide to making the best purchase decisions!', // set false to total remove
|
||||
'url' => false, // Set null for using Url::current(), set false to total remove
|
||||
'type' => false,
|
||||
'site_name' => false,
|
||||
@@ -58,8 +58,8 @@
|
||||
* The default configurations to be used by the json-ld generator.
|
||||
*/
|
||||
'defaults' => [
|
||||
'title' => 'Over 9000 Thousand!', // set false to total remove
|
||||
'description' => 'For those who helped create the Genki Dama', // set false to total remove
|
||||
'title' => 'ProductAlert', // set false to total remove
|
||||
'description' => 'Find top-rated product reviews at ProductAlert. Discover the latest trends, best brands, and right prices. Your guide to making the best purchase decisions!', // set false to total remove
|
||||
'url' => false, // Set to null or 'full' to use Url::full(), set to 'current' to use Url::current(), set false to total remove
|
||||
'type' => 'WebPage',
|
||||
'images' => [],
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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->date('publish_date')->nullable()->after('author_id');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('posts', function (Blueprint $table) {
|
||||
$table->dropColumn('publish_date');
|
||||
});
|
||||
}
|
||||
};
|
||||
1
public/build/assets/NativeImageBlock-bcbff98b.js
Normal file
1
public/build/assets/NativeImageBlock-bcbff98b.js
Normal file
File diff suppressed because one or more lines are too long
0
public/build/assets/NativeImageBlock-e3b0c442.css
Normal file
0
public/build/assets/NativeImageBlock-e3b0c442.css
Normal file
1
public/build/assets/PostEditor-a6038129.js
Normal file
1
public/build/assets/PostEditor-a6038129.js
Normal file
File diff suppressed because one or more lines are too long
83
public/build/assets/VueEditorJs-6310d292.js
Normal file
83
public/build/assets/VueEditorJs-6310d292.js
Normal file
File diff suppressed because one or more lines are too long
17
public/build/assets/admin-app-0df052b8.js
Normal file
17
public/build/assets/admin-app-0df052b8.js
Normal file
File diff suppressed because one or more lines are too long
1
public/build/assets/admin-app-935fc652.css
Normal file
1
public/build/assets/admin-app-935fc652.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
32
public/build/assets/bundle-43b5b4d7.js
Normal file
32
public/build/assets/bundle-43b5b4d7.js
Normal file
File diff suppressed because one or more lines are too long
54
public/build/assets/bundle-94bef551.js
Normal file
54
public/build/assets/bundle-94bef551.js
Normal file
File diff suppressed because one or more lines are too long
@@ -1,4 +1,32 @@
|
||||
{
|
||||
"NativeImageBlock.css": {
|
||||
"file": "assets/NativeImageBlock-e3b0c442.css",
|
||||
"src": "NativeImageBlock.css"
|
||||
},
|
||||
"_NativeImageBlock-bcbff98b.js": {
|
||||
"css": [
|
||||
"assets/NativeImageBlock-e3b0c442.css"
|
||||
],
|
||||
"file": "assets/NativeImageBlock-bcbff98b.js",
|
||||
"imports": [
|
||||
"resources/js/admin-app.js"
|
||||
],
|
||||
"isDynamicEntry": true
|
||||
},
|
||||
"_bundle-43b5b4d7.js": {
|
||||
"file": "assets/bundle-43b5b4d7.js",
|
||||
"imports": [
|
||||
"resources/js/admin-app.js"
|
||||
],
|
||||
"isDynamicEntry": true
|
||||
},
|
||||
"_bundle-94bef551.js": {
|
||||
"file": "assets/bundle-94bef551.js",
|
||||
"imports": [
|
||||
"resources/js/admin-app.js"
|
||||
],
|
||||
"isDynamicEntry": true
|
||||
},
|
||||
"_index-8746c87e.js": {
|
||||
"file": "assets/index-8746c87e.js"
|
||||
},
|
||||
@@ -10,8 +38,20 @@
|
||||
"file": "assets/bootstrap-icons-cfe45b98.woff2",
|
||||
"src": "node_modules/bootstrap-icons/font/fonts/bootstrap-icons.woff2"
|
||||
},
|
||||
"resources/js/admin-app.css": {
|
||||
"file": "assets/admin-app-935fc652.css",
|
||||
"src": "resources/js/admin-app.css"
|
||||
},
|
||||
"resources/js/admin-app.js": {
|
||||
"file": "assets/admin-app-ff7516d6.js",
|
||||
"css": [
|
||||
"assets/admin-app-935fc652.css"
|
||||
],
|
||||
"dynamicImports": [
|
||||
"_NativeImageBlock-bcbff98b.js",
|
||||
"resources/js/vue/PostEditor.vue",
|
||||
"resources/js/vue/VueEditorJs.vue"
|
||||
],
|
||||
"file": "assets/admin-app-0df052b8.js",
|
||||
"imports": [
|
||||
"_index-8746c87e.js"
|
||||
],
|
||||
@@ -26,6 +66,32 @@
|
||||
"isEntry": true,
|
||||
"src": "resources/js/front-app.js"
|
||||
},
|
||||
"resources/js/vue/PostEditor.vue": {
|
||||
"file": "assets/PostEditor-a6038129.js",
|
||||
"imports": [
|
||||
"resources/js/vue/VueEditorJs.vue",
|
||||
"_NativeImageBlock-bcbff98b.js",
|
||||
"_bundle-43b5b4d7.js",
|
||||
"_bundle-94bef551.js",
|
||||
"resources/js/admin-app.js",
|
||||
"_index-8746c87e.js"
|
||||
],
|
||||
"isDynamicEntry": true,
|
||||
"src": "resources/js/vue/PostEditor.vue"
|
||||
},
|
||||
"resources/js/vue/VueEditorJs.vue": {
|
||||
"dynamicImports": [
|
||||
"_bundle-94bef551.js",
|
||||
"_bundle-43b5b4d7.js"
|
||||
],
|
||||
"file": "assets/VueEditorJs-6310d292.js",
|
||||
"imports": [
|
||||
"resources/js/admin-app.js",
|
||||
"_index-8746c87e.js"
|
||||
],
|
||||
"isDynamicEntry": true,
|
||||
"src": "resources/js/vue/VueEditorJs.vue"
|
||||
},
|
||||
"resources/sass/admin-app.scss": {
|
||||
"file": "assets/admin-app-bade20ce.css",
|
||||
"isEntry": true,
|
||||
|
||||
@@ -10,6 +10,7 @@ export const usePostStore = defineStore("postStore", {
|
||||
defaultLocaleSlug: "my",
|
||||
countryLocales: [],
|
||||
localeCategories: [],
|
||||
authors: [],
|
||||
},
|
||||
}),
|
||||
getters: {
|
||||
@@ -22,8 +23,21 @@ export const usePostStore = defineStore("postStore", {
|
||||
localeCategories(state) {
|
||||
return state.data.localeCategories;
|
||||
},
|
||||
authors(state) {
|
||||
return state.data.authors;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async fetchAuthors() {
|
||||
try {
|
||||
const response = await axios.get(route("api.admin.authors"));
|
||||
console.log(response);
|
||||
this.data.authors = response.data.authors;
|
||||
} catch (error) {
|
||||
// alert(error);
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
async fetchCountryLocales() {
|
||||
try {
|
||||
const response = await axios.get(route("api.admin.country-locales"));
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div
|
||||
class="position-absolute w-100 h-100 d-flex justify-content-center text-center"
|
||||
>
|
||||
<div v-if="isUploading" class="align-self-center">
|
||||
<div v-if="isUploading || !isLoaded" class="align-self-center">
|
||||
<div class="spinner-border text-light" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
@@ -34,16 +34,18 @@
|
||||
|
||||
<script>
|
||||
import axios from "axios";
|
||||
import route from "ziggy-js/src/js/index";
|
||||
|
||||
export default {
|
||||
name: "NativeImageBlock",
|
||||
props: {
|
||||
apiUrl: {
|
||||
inputImage: {
|
||||
type: String,
|
||||
default: "https://productalert.test/api/admin/image/upload",
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
data: () => ({
|
||||
isLoaded: false,
|
||||
isUploading: false,
|
||||
imgSrc: null,
|
||||
placeholderSrc: "https://placekitten.com/g/2100/900",
|
||||
@@ -91,7 +93,7 @@ export default {
|
||||
formData.append("file", file);
|
||||
|
||||
axios
|
||||
.post(this.apiUrl, formData, {
|
||||
.post(route("api.admin.upload.cloud.image"), formData, {
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
@@ -115,9 +117,23 @@ export default {
|
||||
this.isUploading = false;
|
||||
});
|
||||
},
|
||||
setInputImage() {
|
||||
if (this.inputImage != null && this.inputImage?.length > 0) {
|
||||
this.imgSrc = this.inputImage;
|
||||
}
|
||||
this.isLoaded = true;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.isUploading = false;
|
||||
|
||||
setTimeout(
|
||||
function () {
|
||||
this.setInputImage();
|
||||
this.isLoaded = true;
|
||||
}.bind(this),
|
||||
3000
|
||||
);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -31,12 +31,13 @@
|
||||
</div>
|
||||
|
||||
<native-image-block
|
||||
ref="imageBlock"
|
||||
class="mb-3"
|
||||
:input-image="post.featured_image"
|
||||
@saved="imageSaved"
|
||||
></native-image-block>
|
||||
|
||||
<div class="card">
|
||||
<div v-if="showEditorJs" class="card">
|
||||
<div class="card-body">
|
||||
<vue-editor-js
|
||||
v-on:saved="editorSaved"
|
||||
@@ -62,8 +63,56 @@
|
||||
Post Status: {{ item }}
|
||||
</option>
|
||||
</select>
|
||||
<button @click="checkAndSave" class="btn btn-primary">
|
||||
Save as {{ post.status }}
|
||||
<div class="fw-bold">Publish Date</div>
|
||||
<div class="input-icon mb-2">
|
||||
<span class="input-icon-addon"
|
||||
><!-- Download SVG icon from http://tabler-icons.io/i/calendar -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="icon"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path
|
||||
d="M4 7a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2v-12z"
|
||||
></path>
|
||||
<path d="M16 3v4"></path>
|
||||
<path d="M8 3v4"></path>
|
||||
<path d="M4 11h16"></path>
|
||||
<path d="M11 15h1"></path>
|
||||
<path d="M12 15v3"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<input
|
||||
type="date"
|
||||
v-model="post.publish_date"
|
||||
class="form-control"
|
||||
placeholder="Select a date"
|
||||
id="datepicker-icon-prepend"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
@click="checkAndSave"
|
||||
class="btn btn-primary"
|
||||
style="height: 50px"
|
||||
>
|
||||
<div
|
||||
v-if="isSaving"
|
||||
class="spinner-border"
|
||||
role="status"
|
||||
:disabled="isSaving"
|
||||
:class="isSaving ? 'disabled' : ''"
|
||||
>
|
||||
<span class="visually-hidden">Saving...</span>
|
||||
</div>
|
||||
<span v-else>Save as {{ post.status }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="card mb-2">
|
||||
@@ -101,6 +150,36 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-2">
|
||||
<div class="card-header fw-bold">Authors</div>
|
||||
<div class="card-body">
|
||||
<div class="py-1" v-for="item in authors" v-bind:key="item.id">
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
:id="item.id"
|
||||
:value="item.id"
|
||||
v-model="post.author_id"
|
||||
/>
|
||||
{{ item.name }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-2">
|
||||
<div class="card-header fw-bold">Other Settings</div>
|
||||
<div class="card-body">
|
||||
<div class="form-check form-switch">
|
||||
<input
|
||||
v-model="post.featured"
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
role="switch"
|
||||
/>
|
||||
<label class="form-check-label">Feature this Post</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -116,16 +195,29 @@ import { mapActions, mapState } from "pinia";
|
||||
|
||||
import { usePostStore } from "@/stores/postStore.js";
|
||||
|
||||
import axios from "axios";
|
||||
import route from "ziggy-js/src/js/index";
|
||||
|
||||
export default {
|
||||
components: { VueEditorJs, List, Header },
|
||||
props: {
|
||||
postId: {
|
||||
type: Number, // The prop type is Number
|
||||
default: null, // Default value if the prop is not provided
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isSaving: false,
|
||||
showEditorJs: false,
|
||||
post: {
|
||||
id: null,
|
||||
title: "",
|
||||
slug: "",
|
||||
excerpt: "",
|
||||
author_id: null,
|
||||
featured: false,
|
||||
publish_date: null,
|
||||
featured_image: null,
|
||||
body: {
|
||||
time: 1591362820044,
|
||||
@@ -179,6 +271,7 @@ export default {
|
||||
"countryLocales",
|
||||
"localeCategories",
|
||||
"defaultLocaleSlug",
|
||||
"authors",
|
||||
]),
|
||||
getPostFullUrl() {
|
||||
if (this.post.slug?.length > 0) {
|
||||
@@ -200,6 +293,7 @@ export default {
|
||||
...mapActions(usePostStore, [
|
||||
"fetchCountryLocales",
|
||||
"fetchLocaleCategories",
|
||||
"fetchAuthors",
|
||||
]),
|
||||
checkAndSave() {
|
||||
let errors = [];
|
||||
@@ -208,6 +302,10 @@ export default {
|
||||
errors.push("post title");
|
||||
}
|
||||
|
||||
if (!(this.post.publish_date?.length > 0)) {
|
||||
errors.push("publish date");
|
||||
}
|
||||
|
||||
if (!(this.post.slug?.length > 0)) {
|
||||
errors.push("post slug");
|
||||
}
|
||||
@@ -241,7 +339,36 @@ export default {
|
||||
this.savePost();
|
||||
}
|
||||
},
|
||||
savePost() {},
|
||||
savePost() {
|
||||
this.isSaving = true;
|
||||
|
||||
const formData = new FormData();
|
||||
|
||||
for (const [key, _item] of Object.entries(this.post)) {
|
||||
if (key == "body") {
|
||||
formData.append(key, JSON.stringify(_item));
|
||||
} else {
|
||||
formData.append(key, _item);
|
||||
}
|
||||
}
|
||||
|
||||
axios
|
||||
.post(route("api.admin.post.upsert"), formData, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
console.warn(response);
|
||||
});
|
||||
|
||||
setTimeout(
|
||||
function () {
|
||||
this.isSaving = false;
|
||||
}.bind(this),
|
||||
1000
|
||||
);
|
||||
},
|
||||
onInitialized(editor) {},
|
||||
imageSaved(src) {
|
||||
this.post.featured_image = src;
|
||||
@@ -278,6 +405,34 @@ export default {
|
||||
}
|
||||
return null;
|
||||
},
|
||||
async fetchPostData(id) {
|
||||
const response = await axios.get(route("api.admin.post.get", { id: id }));
|
||||
|
||||
if (response?.data?.post != null) {
|
||||
let tmp = this.post;
|
||||
let post = response.data.post;
|
||||
|
||||
tmp.id = post.id;
|
||||
tmp.title = post.title;
|
||||
tmp.slug = post.slug;
|
||||
tmp.publish_date = post.publish_date;
|
||||
tmp.excerpt = post.excerpt;
|
||||
tmp.author_id = post.author_id;
|
||||
tmp.featured = post.featured;
|
||||
tmp.featured_image = post.featured_image;
|
||||
tmp.body = post.body;
|
||||
tmp.locale_slug = post.post_category.category.country_locale_slug;
|
||||
tmp.locale_id = post.post_category.category.country_locale_id;
|
||||
tmp.status = post.status;
|
||||
tmp.categories = post.post_category.category.id;
|
||||
|
||||
this.post = tmp;
|
||||
|
||||
this.config.data = post.body;
|
||||
}
|
||||
|
||||
console.log(response.data.post);
|
||||
},
|
||||
slugify: function (title) {
|
||||
var slug = "";
|
||||
// Change to lower case
|
||||
@@ -300,6 +455,25 @@ export default {
|
||||
setTimeout(
|
||||
function () {
|
||||
this.fetchLocaleCategories(this.post.locale_slug);
|
||||
this.fetchAuthors();
|
||||
|
||||
if (this.postId != null) {
|
||||
this.fetchPostData(this.postId).then(() => {
|
||||
setTimeout(
|
||||
function () {
|
||||
this.showEditorJs = true;
|
||||
}.bind(this),
|
||||
1000
|
||||
);
|
||||
});
|
||||
} else {
|
||||
setTimeout(
|
||||
function () {
|
||||
this.showEditorJs = true;
|
||||
}.bind(this),
|
||||
1000
|
||||
);
|
||||
}
|
||||
}.bind(this),
|
||||
100
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const Ziggy = {"url":"https:\/\/productalert.test","port":null,"defaults":{},"routes":{"debugbar.openhandler":{"uri":"_debugbar\/open","methods":["GET","HEAD"]},"debugbar.clockwork":{"uri":"_debugbar\/clockwork\/{id}","methods":["GET","HEAD"]},"debugbar.assets.css":{"uri":"_debugbar\/assets\/stylesheets","methods":["GET","HEAD"]},"debugbar.assets.js":{"uri":"_debugbar\/assets\/javascript","methods":["GET","HEAD"]},"debugbar.cache.delete":{"uri":"_debugbar\/cache\/{key}\/{tags?}","methods":["DELETE"]},"sanctum.csrf-cookie":{"uri":"sanctum\/csrf-cookie","methods":["GET","HEAD"]},"ignition.healthCheck":{"uri":"_ignition\/health-check","methods":["GET","HEAD"]},"ignition.executeSolution":{"uri":"_ignition\/execute-solution","methods":["POST"]},"ignition.updateConfig":{"uri":"_ignition\/update-config","methods":["POST"]},"api.auth.login.post":{"uri":"api\/login","methods":["POST"]},"api.auth.logout.post":{"uri":"api\/logout","methods":["POST"]},"api.admin.country-locales":{"uri":"api\/admin\/country-locales","methods":["GET","HEAD"]},"api.admin.categories":{"uri":"api\/admin\/categories\/{country_locale_slug}","methods":["GET","HEAD"]},"api.admin.upload.cloud.image":{"uri":"api\/admin\/image\/upload","methods":["GET","HEAD"]},"login":{"uri":"login","methods":["GET","HEAD"]},"logout":{"uri":"logout","methods":["POST"]},"register":{"uri":"register","methods":["GET","HEAD"]},"password.request":{"uri":"password\/reset","methods":["GET","HEAD"]},"password.email":{"uri":"password\/email","methods":["POST"]},"password.reset":{"uri":"password\/reset\/{token}","methods":["GET","HEAD"]},"password.update":{"uri":"password\/reset","methods":["POST"]},"password.confirm":{"uri":"password\/confirm","methods":["GET","HEAD"]},"dashboard":{"uri":"admin","methods":["GET","HEAD"]},"about":{"uri":"admin\/about","methods":["GET","HEAD"]},"users.index":{"uri":"admin\/users","methods":["GET","HEAD"]},"posts.manage":{"uri":"admin\/posts","methods":["GET","HEAD"]},"posts.manage.edit":{"uri":"admin\/posts\/edit\/{post_id}","methods":["GET","HEAD"]},"posts.manage.new":{"uri":"admin\/posts\/new","methods":["GET","HEAD"]},"profile.show":{"uri":"admin\/profile","methods":["GET","HEAD"]},"profile.update":{"uri":"admin\/profile","methods":["PUT"]},"home":{"uri":"\/","methods":["GET","HEAD"]},"home.country":{"uri":"{country}","methods":["GET","HEAD"]},"home.country.posts":{"uri":"{country}\/posts","methods":["GET","HEAD"]},"home.country.post":{"uri":"{country}\/posts\/{post_slug}","methods":["GET","HEAD"]},"home.country.category":{"uri":"{country}\/{category}","methods":["GET","HEAD"]}}};
|
||||
const Ziggy = {"url":"https:\/\/productalert.test","port":null,"defaults":{},"routes":{"debugbar.openhandler":{"uri":"_debugbar\/open","methods":["GET","HEAD"]},"debugbar.clockwork":{"uri":"_debugbar\/clockwork\/{id}","methods":["GET","HEAD"]},"debugbar.assets.css":{"uri":"_debugbar\/assets\/stylesheets","methods":["GET","HEAD"]},"debugbar.assets.js":{"uri":"_debugbar\/assets\/javascript","methods":["GET","HEAD"]},"debugbar.cache.delete":{"uri":"_debugbar\/cache\/{key}\/{tags?}","methods":["DELETE"]},"sanctum.csrf-cookie":{"uri":"sanctum\/csrf-cookie","methods":["GET","HEAD"]},"ignition.healthCheck":{"uri":"_ignition\/health-check","methods":["GET","HEAD"]},"ignition.executeSolution":{"uri":"_ignition\/execute-solution","methods":["POST"]},"ignition.updateConfig":{"uri":"_ignition\/update-config","methods":["POST"]},"api.auth.login.post":{"uri":"api\/login","methods":["POST"]},"api.auth.logout.post":{"uri":"api\/logout","methods":["POST"]},"api.admin.post.get":{"uri":"api\/admin\/post\/{id}","methods":["GET","HEAD"]},"api.admin.country-locales":{"uri":"api\/admin\/country-locales","methods":["GET","HEAD"]},"api.admin.categories":{"uri":"api\/admin\/categories\/{country_locale_slug}","methods":["GET","HEAD"]},"api.admin.authors":{"uri":"api\/admin\/authors","methods":["GET","HEAD"]},"api.admin.upload.cloud.image":{"uri":"api\/admin\/image\/upload","methods":["POST"]},"api.admin.post.upsert":{"uri":"api\/admin\/admin\/post\/upsert","methods":["POST"]},"login":{"uri":"login","methods":["GET","HEAD"]},"logout":{"uri":"logout","methods":["POST"]},"register":{"uri":"register","methods":["GET","HEAD"]},"password.request":{"uri":"password\/reset","methods":["GET","HEAD"]},"password.email":{"uri":"password\/email","methods":["POST"]},"password.reset":{"uri":"password\/reset\/{token}","methods":["GET","HEAD"]},"password.update":{"uri":"password\/reset","methods":["POST"]},"password.confirm":{"uri":"password\/confirm","methods":["GET","HEAD"]},"dashboard":{"uri":"admin","methods":["GET","HEAD"]},"about":{"uri":"admin\/about","methods":["GET","HEAD"]},"users.index":{"uri":"admin\/users","methods":["GET","HEAD"]},"posts.manage":{"uri":"admin\/posts","methods":["GET","HEAD"]},"posts.manage.edit":{"uri":"admin\/posts\/edit\/{post_id}","methods":["GET","HEAD"]},"posts.manage.new":{"uri":"admin\/posts\/new","methods":["GET","HEAD"]},"profile.show":{"uri":"admin\/profile","methods":["GET","HEAD"]},"profile.update":{"uri":"admin\/profile","methods":["PUT"]},"home":{"uri":"\/","methods":["GET","HEAD"]},"home.country":{"uri":"{country}","methods":["GET","HEAD"]},"home.country.posts":{"uri":"{country}\/posts","methods":["GET","HEAD"]},"home.country.post":{"uri":"{country}\/posts\/{post_slug}","methods":["GET","HEAD"]},"home.country.category":{"uri":"{country}\/{category}","methods":["GET","HEAD"]}}};
|
||||
|
||||
if (typeof window !== 'undefined' && typeof window.Ziggy !== 'undefined') {
|
||||
Object.assign(Ziggy.routes, window.Ziggy.routes);
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
<th>
|
||||
Image
|
||||
</th>
|
||||
<th>Status</th>
|
||||
<th>Title</th>
|
||||
<th>{{ __('Created at') }}</th>
|
||||
<th>{{ __('Updated in') }}</th>
|
||||
<th>Datetime</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -42,12 +42,33 @@
|
||||
<td><img width="80" height="60" src="{{ $post->featured_image }}"
|
||||
class="img-fluid rounded-2" alt=""></td>
|
||||
<td>
|
||||
@if($post->status === 'publish')
|
||||
<span class="badge bg-success">{{ ucfirst($post->status) }}</span>
|
||||
@elseif($post->status === 'future')
|
||||
<span class="badge bg-primary">{{ ucfirst($post->status) }}</span>
|
||||
@elseif($post->status === 'draft')
|
||||
<span class="badge bg-secondary">{{ ucfirst($post->status) }}</span>
|
||||
@elseif($post->status === 'private')
|
||||
<span class="badge bg-info">{{ ucfirst($post->status) }}</span>
|
||||
@elseif ($post->status == 'trash')
|
||||
<span class="badge bg-danger">{{ ucfirst($post->status) }}</span>
|
||||
@else
|
||||
<span class="badge bg-secondary">{{ ucfirst($post->status) }}</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
@if(!is_empty($post->post_category?->category?->country_locale_slug) && $post->status == 'publish')
|
||||
<a
|
||||
href="{{ route('home.country.post', ['country' => $post->post_category->category->country_locale_slug, 'post_slug' => $post->slug]) }}">{{ $post->title }}</a>
|
||||
href="{{ route('home.country.post', ['country' => $post->post_category?->category?->country_locale_slug, 'post_slug' => $post->slug]) }}">{{ $post->title }}</a>
|
||||
@else
|
||||
{{ $post->title }}
|
||||
@endif
|
||||
|
||||
</td>
|
||||
<td>{{ $post->created_at }}</td>
|
||||
<td>{{ $post->updated_at->diffForhumans() }}</td>
|
||||
<td>
|
||||
Created at {{ $post->created_at->timezone(session()->get('timezone'))->isoFormat('Do MMMM YYYY, h:mm A') }}<br>
|
||||
Updated {{ $post->updated_at->diffForhumans() }}
|
||||
</td>
|
||||
<td>
|
||||
<div><a href="{{ route('posts.manage.edit', ['post_id' => $post->id]) }}"
|
||||
class="btn">Edit</a></div>
|
||||
|
||||
@@ -11,14 +11,17 @@
|
||||
@else
|
||||
New Post
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-body">
|
||||
<div class="container-xl">
|
||||
@if (!is_null($post))
|
||||
<post-editor :post-id="{{ $post->id }}"></post-editor>
|
||||
@else
|
||||
<post-editor></post-editor>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@@ -31,10 +31,10 @@
|
||||
<h2 class="h5">{{ $post->excerpt }}</h2>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<img src="{{ $post->featured_image }}" alt="" class="img-fluid rounded-3">
|
||||
<img src="{{ $post->featured_image }}" alt="Photo of {{ $post->name }}" class="img-fluid rounded-3">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
{{ $post->html_body }}
|
||||
{!! $post->html_body !!}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -5,8 +5,11 @@
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="">
|
||||
<title>{{ config('app.name', 'Laravel') }}</title>
|
||||
{!! SEOMeta::generate() !!}
|
||||
{!! OpenGraph::generate() !!}
|
||||
{!! Twitter::generate() !!}
|
||||
{!! JsonLdMulti::generate() !!}
|
||||
<meta property="fb:app_id" content="{{ config('seotools.fb_app_id') }}" />
|
||||
|
||||
@vite('resources/sass/front-app.scss')
|
||||
|
||||
|
||||
@@ -1,35 +1,34 @@
|
||||
<div class="container-fluid border-top">
|
||||
<footer class="py-5 container">
|
||||
<div class="row">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-6 col-md-2 mb-3">
|
||||
<ul class="nav flex-column">
|
||||
|
||||
@foreach ($categories as $category)
|
||||
@if ($category->id % 2 == 0)
|
||||
<li class="nav-item mb-2">
|
||||
<a class="nav-link p-0 text-body-secondary"
|
||||
href="{{ route('home.country.category', ['country' => $category->country_locale_slug, 'category' => $category->slug]) }}">{{ $category->name }}</a>
|
||||
</li>
|
||||
@endif
|
||||
@endforeach
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-6 col-md-2 mb-3">
|
||||
<ul class="nav flex-column">
|
||||
@foreach ($categories as $category)
|
||||
@if ($category->id % 2 == 1)
|
||||
<li class="nav-item mb-2">
|
||||
<a href="#" class="nav-link p-0 text-body-secondary">About Us</a>
|
||||
</li>
|
||||
<li class="nav-item mb-2">
|
||||
<a href="#" class="nav-link p-0 text-body-secondary">Contact Us</a>
|
||||
</li>
|
||||
<li class="nav-item mb-2">
|
||||
<a href="#" class="nav-link p-0 text-body-secondary">Advertise with us</a>
|
||||
<a class="nav-link p-0 text-body-secondary"
|
||||
href="{{ route('home.country.category', ['country' => $category->country_locale_slug, 'category' => $category->slug]) }}">{{ $category->name }}</a>
|
||||
</li>
|
||||
@endif
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-md-5 offset-md-1 mb-3">
|
||||
<div class="col-md-5 mb-3">
|
||||
|
||||
|
||||
@if ($country_locales->count() > 1)
|
||||
@@ -52,15 +51,15 @@
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form>
|
||||
{{-- <form>
|
||||
<h5>Subscribe to our newsletter</h5>
|
||||
<p>Monthly digest of what's new and exciting from us.</p>
|
||||
<div class="d-flex flex-column flex-sm-row w-100 gap-2">
|
||||
<label for="newsletter1" class="visually-hidden">Email address</label>
|
||||
<input id="newsletter1" type="text" class="form-control" placeholder="Email address">
|
||||
<input id="newsletter1" type="disabled" class="form-control disabled" placeholder="Email address">
|
||||
<button class="btn btn-primary" type="button">Subscribe</button>
|
||||
</div>
|
||||
</form>
|
||||
</form> --}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
use App\Models\CountryLocale;
|
||||
use App\Models\Post;
|
||||
use App\Models\Author;
|
||||
use App\Models\Category;
|
||||
use App\Models\CountryLocale;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@@ -17,30 +17,44 @@
|
||||
|
|
||||
*/
|
||||
|
||||
Route::post('login', [App\Http\Controllers\Auth\LoginController::class, 'login'])->name('api.auth.login.post');
|
||||
Route::post('login', [App\Http\Controllers\Auth\LoginController::class, 'login'])->name('api.auth.login.post');
|
||||
|
||||
Route::middleware('auth:sanctum')->post('logout',[App\Http\Controllers\Auth\LoginController::class,'logout'])->name('api.auth.logout.post');
|
||||
Route::middleware('auth:sanctum')->post('logout', [App\Http\Controllers\Auth\LoginController::class, 'logout'])->name('api.auth.logout.post');
|
||||
|
||||
Route::prefix('admin')->middleware('auth:sanctum')->group(function () {
|
||||
|
||||
Route::get('/country-locales', function() {
|
||||
Route::get('/post/{id}', function ($id) {
|
||||
$post = Post::with('post_category.category')->find($id);
|
||||
|
||||
return response()->json(compact('post'));
|
||||
|
||||
})->name('api.admin.post.get');
|
||||
|
||||
|
||||
Route::get('/country-locales', function () {
|
||||
$country_locales = CountryLocale::where('enabled', true)->get();
|
||||
$default_locale_slug = 'my';
|
||||
|
||||
return response()->json(compact('country_locales','default_locale_slug'));
|
||||
return response()->json(compact('country_locales', 'default_locale_slug'));
|
||||
|
||||
})->name('api.admin.country-locales');
|
||||
|
||||
Route::get('/categories/{country_locale_slug}', function($country_locale_slug) {
|
||||
Route::get('/categories/{country_locale_slug}', function ($country_locale_slug) {
|
||||
$categories = Category::where('enabled', true)->where('country_locale_slug', $country_locale_slug)->get();
|
||||
|
||||
return response()->json(compact('categories'));
|
||||
|
||||
})->name('api.admin.categories');
|
||||
|
||||
Route::get('/authors', function () {
|
||||
$authors = Author::where('enabled', true)->get();
|
||||
|
||||
return response()->json(compact('authors'));
|
||||
|
||||
})->name('api.admin.authors');
|
||||
|
||||
Route::post('image/upload', [App\Http\Controllers\Services\ImageUploadController::class, 'index'])->name('api.admin.upload.cloud.image');
|
||||
|
||||
Route::post('admin/post/upsert', [App\Http\Controllers\Admin\PostController::class, 'postUpsert'])->name('api.admin.post.upsert');
|
||||
|
||||
});
|
||||
|
||||
Route::post('admin/image/upload', [App\Http\Controllers\Services\ImageUploadController::class, 'index'])->name('api.admin.upload.cloud.image');
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user