diff --git a/TODO.md b/TODO.md
index a383b78..42a22d4 100644
--- a/TODO.md
+++ b/TODO.md
@@ -3,7 +3,7 @@
### Admin
- [x] CRUD Info
-- [ ] CRUD Banner
+- [x] CRUD Banner
- [ ] CRUD Rekening / Account
- [ ] CRUD Customer
- [ ] CRUD Voucher
diff --git a/app/Http/Controllers/BannerController.php b/app/Http/Controllers/BannerController.php
new file mode 100644
index 0000000..04ba868
--- /dev/null
+++ b/app/Http/Controllers/BannerController.php
@@ -0,0 +1,83 @@
+paginate();
+
+ return inertia('Banner/Index', [
+ 'query' => $query
+ ]);
+ }
+
+ public function create()
+ {
+ return inertia('Banner/Form');
+ }
+
+ public function store(Request $request)
+ {
+ $request->validate([
+ 'image' => 'required|image',
+ 'title' => 'required|string',
+ 'description' => 'required|string',
+ ]);
+
+ $file = $request->file('image');
+ $file->store('uploads', 'public');
+
+ Banner::create([
+ 'image' => $file->hashName('uploads'),
+ 'title' => $request->title,
+ 'description' => $request->description,
+ ]);
+
+ return redirect()->route('banner.index')
+ ->with('message', ['type' => 'success', 'message' => 'Item has beed saved']);
+ }
+
+ public function edit(Banner $banner)
+ {
+ return inertia('Banner/Form', [
+ 'banner' => $banner
+ ]);
+ }
+
+ public function update(Request $request, Banner $banner)
+ {
+ $request->validate([
+ 'image' => 'nullable|image',
+ 'title' => 'required|string',
+ 'description' => 'required|string',
+ ]);
+
+ if ($request->hasFile('image')) {
+ $file = $request->file('image');
+ $file->store('uploads', 'public');
+ $banner->image = $file->hashName('uploads');
+ }
+
+ $banner->update([
+ 'image' => $banner->image,
+ 'title' => $request->title,
+ 'description' => $request->description,
+ ]);
+
+ return redirect()->route('banner.index')
+ ->with('message', ['type' => 'success', 'message' => 'Item has beed updated']);
+ }
+
+ public function destroy(Banner $banner)
+ {
+ $banner->delete();
+
+ return redirect()->route('banner.index')
+ ->with('message', ['type' => 'success', 'message' => 'Item has beed deleted']);
+ }
+}
diff --git a/app/Http/Controllers/Customer/AuthController.php b/app/Http/Controllers/Customer/AuthController.php
index 21c8261..507e671 100644
--- a/app/Http/Controllers/Customer/AuthController.php
+++ b/app/Http/Controllers/Customer/AuthController.php
@@ -73,7 +73,7 @@ class AuthController extends Controller
'fullname' => $user->name,
'name' => $user->nickname,
'email' => $user->email,
- 'username' => Str::random(10),
+ 'username' => Str::slug($user->name . '_' . Str::random(5), '_'),
'google_id' => $user->id,
'google_oauth_response' => json_encode($user),
'customer_level_id' => $basic->id,
diff --git a/app/Http/Controllers/Customer/HomeController.php b/app/Http/Controllers/Customer/HomeController.php
index 10756c3..2c60801 100644
--- a/app/Http/Controllers/Customer/HomeController.php
+++ b/app/Http/Controllers/Customer/HomeController.php
@@ -3,6 +3,7 @@
namespace App\Http\Controllers\Customer;
use App\Http\Controllers\Controller;
+use App\Models\Banner;
use App\Models\Info;
class HomeController extends Controller
@@ -10,9 +11,18 @@ class HomeController extends Controller
public function index()
{
$infos = Info::where('is_publish', 1)->orderBy('updated_at', 'desc')->get();
+ $banners = Banner::orderBy('updated_at', 'desc')->get();
return inertia('Home/Index/Index', [
'infos' => $infos,
+ 'banners' => $banners
+ ]);
+ }
+
+ public function banner(Banner $banner)
+ {
+ return inertia('Home/Index/Banner', [
+ 'banner' => $banner,
]);
}
}
diff --git a/app/Http/Controllers/GeneralController.php b/app/Http/Controllers/GeneralController.php
index 0559b8b..5e8209c 100644
--- a/app/Http/Controllers/GeneralController.php
+++ b/app/Http/Controllers/GeneralController.php
@@ -2,6 +2,9 @@
namespace App\Http\Controllers;
+use Illuminate\Http\Request;
+use Illuminate\Support\Str;
+
class GeneralController extends Controller
{
public function index()
@@ -13,4 +16,18 @@ class GeneralController extends Controller
{
return inertia('Maintance');
}
+
+ public function upload(Request $request)
+ {
+ $request->validate(['image' => 'required|file']);
+ $file = $request->file('image');
+ $file->store('uploads', 'public');
+
+
+ return response()->json([
+ 'id' => Str::ulid(),
+ 'name' => $file->getClientOriginalName(),
+ 'url' => asset($file->hashName('uploads')),
+ ]);
+ }
}
diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php
index 6d5b532..592894d 100644
--- a/app/Http/Middleware/HandleInertiaRequests.php
+++ b/app/Http/Middleware/HandleInertiaRequests.php
@@ -37,6 +37,7 @@ class HandleInertiaRequests extends Middleware
'message' => fn () => $request->session()->get('message'),
],
'app_name' => env('APP_NAME', 'App Name'),
+ 'csrf_token' => csrf_token(),
]);
}
}
diff --git a/app/Models/Banner.php b/app/Models/Banner.php
index e643a9f..b895462 100644
--- a/app/Models/Banner.php
+++ b/app/Models/Banner.php
@@ -2,6 +2,8 @@
namespace App\Models;
+use Illuminate\Database\Eloquent\Casts\Attribute;
+
class Banner extends Model
{
protected $fillable = [
@@ -11,4 +13,15 @@ class Banner extends Model
'destination',
'type',
];
+
+ protected $appends = [
+ 'image_url'
+ ];
+
+ protected function imageUrl(): Attribute
+ {
+ return Attribute::make(get: function () {
+ return asset($this->image);
+ });
+ }
}
diff --git a/app/Models/Customer.php b/app/Models/Customer.php
index bf70725..f896616 100644
--- a/app/Models/Customer.php
+++ b/app/Models/Customer.php
@@ -41,6 +41,7 @@ class Customer extends Authenticatable
'image_url',
'display_deposit',
'display_coin',
+ 'display_phone'
];
public function imageUrl(): Attribute
@@ -62,6 +63,16 @@ class Customer extends Authenticatable
);
}
+ public function displayPhone(): Attribute
+ {
+ return Attribute::make(get: function () {
+ if ($this->phone === null) {
+ return ' - ';
+ }
+ return '+62' . $this->phone;
+ });
+ }
+
public function displayDeposit(): Attribute
{
return Attribute::make(get: function () {
diff --git a/database/migrations/2023_05_24_130511_create_banners_table.php b/database/migrations/2023_05_24_130511_create_banners_table.php
index bdedd5b..8a0aea7 100644
--- a/database/migrations/2023_05_24_130511_create_banners_table.php
+++ b/database/migrations/2023_05_24_130511_create_banners_table.php
@@ -16,7 +16,7 @@ return new class extends Migration
$table->string('image');
$table->string('title');
- $table->string('description')->nullable();
+ $table->text('description')->nullable();
$table->string('destination')->nullable();
$table->string('type')->nullable();
$table->smallInteger('is_publish')->nullable();
diff --git a/database/seeders/DummySeeder.php b/database/seeders/DummySeeder.php
index 7e028ae..6df9eac 100644
--- a/database/seeders/DummySeeder.php
+++ b/database/seeders/DummySeeder.php
@@ -2,6 +2,7 @@
namespace Database\Seeders;
+use App\Models\Banner;
use App\Models\Info;
use Illuminate\Database\Seeder;
@@ -15,6 +16,7 @@ class DummySeeder extends Seeder
public function run()
{
$this->info();
+ $this->banner();
}
public function info()
@@ -24,4 +26,16 @@ class DummySeeder extends Seeder
'is_publish' => 1,
]);
}
+
+ public function banner()
+ {
+ $images = ['1.webp', '2.webp', '3.webp'];
+ foreach ($images as $index => $image) {
+ Banner::create([
+ 'title' => 'Banner ' . $index,
+ 'image' => 'sample/' . $image,
+ 'description' => '
Banner
'
+ ]);
+ }
+ }
}
diff --git a/package-lock.json b/package-lock.json
index b494748..9badb38 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5,6 +5,7 @@
"packages": {
"": {
"dependencies": {
+ "@tinymce/tinymce-react": "^4.3.0",
"flowbite": "^1.6.3",
"flowbite-react": "^0.3.8",
"is": "^3.3.0",
@@ -15,7 +16,8 @@
"react-icons": "^4.7.1",
"react-number-format": "^5.1.2",
"react-toastify": "^9.1.1",
- "react-use": "^17.4.0"
+ "react-use": "^17.4.0",
+ "tinymce": "^6.4.2"
},
"devDependencies": {
"@headlessui/react": "^1.4.2",
@@ -930,6 +932,19 @@
"tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1"
}
},
+ "node_modules/@tinymce/tinymce-react": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tinymce/tinymce-react/-/tinymce-react-4.3.0.tgz",
+ "integrity": "sha512-iB4cUsYfcJL4NGuKhqCGYuTmFTje3nPxyPv1HxprTsp/YMGuuiiSNWrv3zwI31QX5Cn8qeq9MrMDnbxuRugHyg==",
+ "dependencies": {
+ "prop-types": "^15.6.2",
+ "tinymce": "^6.3.1"
+ },
+ "peerDependencies": {
+ "react": "^18.0.0 || ^17.0.1 || ^16.7.0",
+ "react-dom": "^18.0.0 || ^17.0.1 || ^16.7.0"
+ }
+ },
"node_modules/@types/js-cookie": {
"version": "2.2.7",
"resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-2.2.7.tgz",
@@ -2825,6 +2840,11 @@
"node": ">=10"
}
},
+ "node_modules/tinymce": {
+ "version": "6.4.2",
+ "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-6.4.2.tgz",
+ "integrity": "sha512-te+4c8PoAwTKPMBQtMQehnSZlOO9Ay5tDgaRFJKBehYb6SlX2PYZ0v3oe/cmiv5EfqdwZLkEMXk2MNOeApZZLg=="
+ },
"node_modules/to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
diff --git a/package.json b/package.json
index 0a2f7eb..3f97a79 100644
--- a/package.json
+++ b/package.json
@@ -20,16 +20,18 @@
"vite": "^4.0.0"
},
"dependencies": {
+ "@tinymce/tinymce-react": "^4.3.0",
"flowbite": "^1.6.3",
"flowbite-react": "^0.3.8",
- "react-icons": "^4.7.1",
"is": "^3.3.0",
"moment": "^2.29.4",
"nprogress": "^0.2.0",
"qs": "^6.11.0",
"react-datepicker": "^4.8.0",
+ "react-icons": "^4.7.1",
"react-number-format": "^5.1.2",
"react-toastify": "^9.1.1",
- "react-use": "^17.4.0"
+ "react-use": "^17.4.0",
+ "tinymce": "^6.4.2"
}
-}
\ No newline at end of file
+}
diff --git a/public/uploads/2FlN0wGNWeaxv9kFA9SOoh9JeTwRvUEiV5a8faRx.png b/public/uploads/2FlN0wGNWeaxv9kFA9SOoh9JeTwRvUEiV5a8faRx.png
new file mode 100644
index 0000000..3635370
Binary files /dev/null and b/public/uploads/2FlN0wGNWeaxv9kFA9SOoh9JeTwRvUEiV5a8faRx.png differ
diff --git a/public/uploads/5Cb26LsXe6x8o2C1NDeqPhpvK305Y05HmzWz6OlX.png b/public/uploads/5Cb26LsXe6x8o2C1NDeqPhpvK305Y05HmzWz6OlX.png
new file mode 100644
index 0000000..b36f112
Binary files /dev/null and b/public/uploads/5Cb26LsXe6x8o2C1NDeqPhpvK305Y05HmzWz6OlX.png differ
diff --git a/public/uploads/GXhu1GNCg4KpAgAVZvS1Bu4X24GRYhU6VBkWtFe9.png b/public/uploads/GXhu1GNCg4KpAgAVZvS1Bu4X24GRYhU6VBkWtFe9.png
new file mode 100644
index 0000000..b36f112
Binary files /dev/null and b/public/uploads/GXhu1GNCg4KpAgAVZvS1Bu4X24GRYhU6VBkWtFe9.png differ
diff --git a/public/uploads/kjFUmhXj0s0xAkhf4IRQT470njODmLgMlJyw0x37.png b/public/uploads/kjFUmhXj0s0xAkhf4IRQT470njODmLgMlJyw0x37.png
new file mode 100644
index 0000000..80ff33a
Binary files /dev/null and b/public/uploads/kjFUmhXj0s0xAkhf4IRQT470njODmLgMlJyw0x37.png differ
diff --git a/resources/js/Components/TinyMCE.jsx b/resources/js/Components/TinyMCE.jsx
new file mode 100644
index 0000000..c1eba5b1
--- /dev/null
+++ b/resources/js/Components/TinyMCE.jsx
@@ -0,0 +1,165 @@
+import { Editor } from '@tinymce/tinymce-react'
+
+// TinyMCE so the global var exists
+// eslint-disable-next-line no-unused-vars
+import tinymce from 'tinymce/tinymce'
+// DOM model
+import 'tinymce/models/dom/model'
+// Theme
+import 'tinymce/themes/silver'
+// Toolbar icons
+import 'tinymce/icons/default'
+// Editor styles
+import 'tinymce/skins/ui/oxide/skin.min.css'
+
+// importing the plugin js.
+// if you use a plugin that is not listed here the editor will fail to load
+import 'tinymce/plugins/advlist'
+import 'tinymce/plugins/anchor'
+import 'tinymce/plugins/autolink'
+import 'tinymce/plugins/autoresize'
+import 'tinymce/plugins/autosave'
+import 'tinymce/plugins/charmap'
+import 'tinymce/plugins/code'
+import 'tinymce/plugins/codesample'
+import 'tinymce/plugins/directionality'
+import 'tinymce/plugins/emoticons'
+import 'tinymce/plugins/fullscreen'
+import 'tinymce/plugins/help'
+import 'tinymce/plugins/image'
+import 'tinymce/plugins/importcss'
+import 'tinymce/plugins/insertdatetime'
+import 'tinymce/plugins/link'
+import 'tinymce/plugins/lists'
+import 'tinymce/plugins/media'
+import 'tinymce/plugins/nonbreaking'
+import 'tinymce/plugins/pagebreak'
+import 'tinymce/plugins/preview'
+import 'tinymce/plugins/quickbars'
+import 'tinymce/plugins/save'
+import 'tinymce/plugins/searchreplace'
+import 'tinymce/plugins/table'
+import 'tinymce/plugins/template'
+import 'tinymce/plugins/visualblocks'
+import 'tinymce/plugins/visualchars'
+import 'tinymce/plugins/wordcount'
+
+// importing plugin resources
+import 'tinymce/plugins/emoticons/js/emojis'
+
+// Content styles, including inline UI like fake cursors
+/* eslint import/no-webpack-loader-syntax: off */
+import contentCss from 'tinymce/skins/content/default/content.min.css?inline'
+import contentUiCss from 'tinymce/skins/ui/oxide/content.min.css?inline'
+
+import generalCss from '../../css/app.css?inline'
+
+import { usePage } from '@inertiajs/react'
+
+export default function BundledEditor(props) {
+ const { init, ...rest } = props
+ const { csrf_token } = usePage().props
+
+ const FilePickerCallback = async (callback, value, meta) => {
+ // Provide file and text for the link dialog
+ const input = document.createElement('input')
+ input.setAttribute('type', 'file')
+ input.setAttribute('accept', 'image/*,video/*')
+
+ input.addEventListener('change', async (e) => {
+ const body = new FormData()
+ body.append('_token', csrf_token)
+ body.append('image', e.target.files[0])
+
+ await fetch(route('post.upload'), {
+ method: 'post',
+ body: body,
+ headers: {
+ 'accept-content': 'application/json',
+ 'X-CSSRF-TOKEN': csrf_token,
+ },
+ credentials: 'include',
+ })
+ .then((res) => res.json())
+ .then((res) => {
+ callback(res.url, { alt: 'My alt text' })
+ })
+ .catch((err) => {
+ alert(err)
+ })
+ })
+
+ input.click()
+ }
+
+ const ImageUploadHandler = (blobInfo, progress) =>
+ new Promise((resolve, reject) => {
+ const xhr = new XMLHttpRequest()
+ xhr.withCredentials = true
+ xhr.open('POST', route('post.upload'))
+
+ xhr.upload.onprogress = (e) => {
+ progress((e.loaded / e.total) * 100)
+ }
+
+ xhr.onload = () => {
+ if (xhr.status === 403) {
+ reject({
+ message: 'HTTP Error: ' + xhr.status,
+ remove: true,
+ })
+ return
+ }
+
+ if (xhr.status < 200 || xhr.status >= 300) {
+ reject('HTTP Error: ' + xhr.status)
+ return
+ }
+
+ const json = JSON.parse(xhr.responseText)
+
+ if (!json || typeof json.url != 'string') {
+ reject('Invalid JSON: ' + xhr.responseText)
+ return
+ }
+
+ resolve(json.url)
+ }
+
+ xhr.onerror = () => {
+ reject(
+ 'Image upload failed due to a XHR Transport error. Code: ' +
+ xhr.status
+ )
+ }
+
+ const formData = new FormData()
+ formData.append('_token', csrf_token)
+ formData.append('image', blobInfo.blob(), blobInfo.filename())
+
+ xhr.send(formData)
+ })
+
+ // note that skin and content_css is disabled to avoid the normal
+ // loading process and is instead loaded as a string via content_style
+ return (
+
+ )
+}
diff --git a/resources/js/Layouts/Partials/routes.js b/resources/js/Layouts/Partials/routes.js
index c393f96..991bbc7 100644
--- a/resources/js/Layouts/Partials/routes.js
+++ b/resources/js/Layouts/Partials/routes.js
@@ -1,4 +1,10 @@
-import { HiChartPie, HiUser, HiUsers, HiUserGroup } from 'react-icons/hi'
+import {
+ HiChartPie,
+ HiUser,
+ HiUsers,
+ HiUserGroup,
+ HiInformationCircle,
+} from 'react-icons/hi'
import { HiQuestionMarkCircle } from 'react-icons/hi2'
export default [
@@ -10,6 +16,14 @@ export default [
active: 'dashboard',
permission: 'view-dashboard',
},
+ {
+ name: 'Banner',
+ show: true,
+ icon: HiInformationCircle,
+ route: route('banner.index'),
+ active: 'banner.*',
+ permission: 'view-banner',
+ },
{
name: 'Info',
show: true,
diff --git a/resources/js/Pages/Banner/Form.jsx b/resources/js/Pages/Banner/Form.jsx
new file mode 100644
index 0000000..e9c9ed9
--- /dev/null
+++ b/resources/js/Pages/Banner/Form.jsx
@@ -0,0 +1,125 @@
+import React, { useEffect, Suspense } from 'react'
+import { isEmpty } from 'lodash'
+
+import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout'
+import FormInput from '@/Components/FormInput'
+import Button from '@/Components/Button'
+import { Head, useForm } from '@inertiajs/react'
+import FormFile from '@/Components/FormFile'
+
+const TinyEditor = React.lazy(() => import('@/Components/TinyMCE'))
+
+export default function Form(props) {
+ const { banner } = props
+
+ const { data, setData, post, processing, errors } = useForm({
+ title: '',
+ description: '',
+ image: '',
+ image_url: '',
+ })
+
+ const handleOnChange = (event) => {
+ setData(
+ event.target.name,
+ event.target.type === 'checkbox'
+ ? event.target.checked
+ ? 1
+ : 0
+ : event.target.value
+ )
+ }
+ const handleSubmit = () => {
+ if (isEmpty(banner) === false) {
+ post(route('banner.update', banner))
+ return
+ }
+ post(route('banner.store'))
+ }
+
+ useEffect(() => {
+ if (isEmpty(banner) === false) {
+ setData({
+ title: banner.title,
+ description: banner.description,
+ image_url: banner.image_url,
+ })
+ }
+ }, [banner])
+
+ return (
+
+
+
+
+
+
+
Banner
+
+
+ setData('image', e.target.files[0])
+ }
+ error={errors.image}
+ preview={
+ isEmpty(data.image_url) === false && (
+
+ )
+ }
+ />
+
+
+ Loading...
}>
+ {
+ setData(
+ 'description',
+ editor.getContent()
+ )
+ }}
+ />
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/resources/js/Pages/Banner/Index.jsx b/resources/js/Pages/Banner/Index.jsx
new file mode 100644
index 0000000..03f690b
--- /dev/null
+++ b/resources/js/Pages/Banner/Index.jsx
@@ -0,0 +1,143 @@
+import React, { useEffect, useState } from 'react'
+import { Link, router } from '@inertiajs/react'
+import { usePrevious } from 'react-use'
+import { Head } from '@inertiajs/react'
+import { Button, Dropdown } from 'flowbite-react'
+import { HiPencil, HiTrash } from 'react-icons/hi'
+import { useModalState } from '@/hooks'
+
+import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout'
+import Pagination from '@/Components/Pagination'
+import ModalConfirm from '@/Components/ModalConfirm'
+import { hasPermission } from '@/utils'
+
+export default function Info(props) {
+ const {
+ query: { links, data },
+ auth,
+ } = props
+
+ const confirmModal = useModalState()
+
+ const handleDeleteClick = (banner) => {
+ confirmModal.setData(banner)
+ confirmModal.toggle()
+ }
+
+ const onDelete = () => {
+ if (confirmModal.data !== null) {
+ router.delete(route('banner.destroy', confirmModal.data.id))
+ }
+ }
+
+ const canCreate = hasPermission(auth, 'create-banner')
+ const canUpdate = hasPermission(auth, 'update-banner')
+ const canDelete = hasPermission(auth, 'delete-banner')
+
+ return (
+
+
+
+
+
+
+
+ {canCreate && (
+
+
+
+ )}
+
+
+
+
+
+
+
+ Judul
+ |
+ |
+
+
+
+ {data.map((banner) => (
+
+
+ {banner.title}
+ |
+
+
+ {canUpdate && (
+
+
+
+
+ Ubah
+
+
+
+ )}
+ {canDelete && (
+
+ handleDeleteClick(
+ banner
+ )
+ }
+ >
+
+
+ )}
+
+ |
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/resources/js/Pages/Home/Base.jsx b/resources/js/Pages/Home/Base.jsx
index a4a5ad3..e6b6126 100644
--- a/resources/js/Pages/Home/Base.jsx
+++ b/resources/js/Pages/Home/Base.jsx
@@ -6,7 +6,7 @@ export default function Index({ status }) {
return (
-
+
diff --git a/resources/js/Pages/Home/Index/Banner.jsx b/resources/js/Pages/Home/Index/Banner.jsx
new file mode 100644
index 0000000..b2aac39
--- /dev/null
+++ b/resources/js/Pages/Home/Index/Banner.jsx
@@ -0,0 +1,21 @@
+import React from 'react'
+import { Head } from '@inertiajs/react'
+import CustomerLayout from '@/Layouts/CustomerLayout'
+
+export default function Banner({ banner }) {
+ return (
+
+
+
+
+
+ {banner.title}
+
+
+
+
+ )
+}
diff --git a/resources/js/Pages/Home/Index/Index.jsx b/resources/js/Pages/Home/Index/Index.jsx
index efdd939..8faf39e 100644
--- a/resources/js/Pages/Home/Index/Index.jsx
+++ b/resources/js/Pages/Home/Index/Index.jsx
@@ -1,5 +1,5 @@
import React from 'react'
-import { Head, usePage } from '@inertiajs/react'
+import { Head, router, usePage } from '@inertiajs/react'
import CustomerLayout from '@/Layouts/CustomerLayout'
import { HiOutlineBell } from 'react-icons/hi2'
@@ -29,7 +29,11 @@ const GuestBanner = () => {
)
}
-export default function Index({ auth: { user }, infos }) {
+export default function Index({ auth: { user }, infos, banners }) {
+ const handleBanner = (banner) => {
+ router.get(route('home.banner', banner))
+ }
+
return (
@@ -39,23 +43,16 @@ export default function Index({ auth: { user }, infos }) {
{/* banner */}
-
-
-
-
-
+ {banners.map((banner) => (
+
handleBanner(banner)}
+ key={banner.id}
+ src={banner.image_url}
+ className={`rounded w-${
+ banners.length === 1 ? 'full' : '[80%]'
+ } min-w-[340px] h-28 object-cover`}
+ />
+ ))}
diff --git a/resources/js/Pages/Home/Index/UserBanner.jsx b/resources/js/Pages/Home/Index/UserBanner.jsx
index 6ed4b66..7d00114 100644
--- a/resources/js/Pages/Home/Index/UserBanner.jsx
+++ b/resources/js/Pages/Home/Index/UserBanner.jsx
@@ -9,7 +9,7 @@ export default function UserBanner({ user }) {
{user.name}
-
+62{user.phone}
+
{user.display_phone}
{user.level.name}
diff --git a/resources/js/Pages/Home/Profile/Index.jsx b/resources/js/Pages/Home/Profile/Index.jsx
index a95330e..fbab70d 100644
--- a/resources/js/Pages/Home/Profile/Index.jsx
+++ b/resources/js/Pages/Home/Profile/Index.jsx
@@ -42,7 +42,7 @@ export default function Index({ auth: { user } }) {
{user.name}
-
+62{user.phone}
+
{user.display_phone}
{user.level.name}
diff --git a/routes/admin.php b/routes/admin.php
index 3f9e720..2027157 100644
--- a/routes/admin.php
+++ b/routes/admin.php
@@ -1,6 +1,7 @@
name('info.store');
Route::put('/infos/{info}', [InfoController::class, 'update'])->name('info.update');
Route::delete('/infos/{info}', [InfoController::class, 'destroy'])->name('info.destroy');
+
+ // upload
+ Route::post('/upload', [GeneralController::class, 'upload'])->name('post.upload');
+
+ // banner
+ Route::get('/banner', [BannerController::class, 'index'])->name('banner.index');
+ Route::get('/banner/create', [BannerController::class, 'create'])->name('banner.create');
+ Route::post('/banner', [BannerController::class, 'store'])->name('banner.store');
+ Route::get('/banner/{banner}', [BannerController::class, 'edit'])->name('banner.edit');
+ Route::post('/banner/{banner}', [BannerController::class, 'update'])->name('banner.update');
+ Route::delete('/banner/{banner}', [BannerController::class, 'destroy'])->name('banner.destroy');
});
});
diff --git a/routes/web.php b/routes/web.php
index 23d3ac8..a5feafe 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -19,6 +19,8 @@ use Illuminate\Support\Facades\Route;
Route::middleware(['http_secure_aware', 'guard_should_customer', 'inertia.customer'])->group(function () {
Route::get('/', [HomeController::class, 'index'])->name('home.index');
+ Route::get('/banner/{banner}', [HomeController::class, 'banner'])->name('home.banner');
+
Route::middleware('auth:customer')->group(function () {
// profile
Route::get('profile', [ProfileController::class, 'index'])->name('customer.profile.index');