customer crud done

dev
Aji Kamaludin 1 year ago
parent 84bec3df53
commit 2503b20e33
No known key found for this signature in database
GPG Key ID: 19058F67F0083AD3

@ -0,0 +1,29 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Customer;
use Illuminate\Http\Request;
class CustomerController extends Controller
{
public function index(Request $request)
{
$query = Customer::query();
if ($request->q) {
$query->where('name', 'like', "%{$request->q}%");
}
if ($request->except_id) {
$query->where('id', '!=', $request->except_id);
}
if ($request->all == 1) {
return $query->get();
}
return $query->get();
}
}

@ -0,0 +1,74 @@
<?php
namespace App\Http\Controllers;
use App\Models\Customer;
use Illuminate\Http\Request;
class CustomerController extends Controller
{
public function index(Request $request)
{
$query = Customer::query();
if ($request->q) {
$query->where('name', 'like', "%{$request->q}%")
->orWhere('code', 'like', "%{$request->q}%");
}
$query->orderBy('created_at', 'desc');
return inertia('Customer/Index', [
'query' => $query->paginate(),
]);
}
public function store(Request $request)
{
$request->validate([
'code' => 'required|string|max:255',
'name' => 'required|string|max:255',
'point' => 'required|numeric',
]);
Customer::create([
'code' => $request->code,
'name' => $request->name,
'start_point' => $request->point,
'last_point' => $request->point,
]);
return redirect()->route('customer.index')
->with('message', ['type' => 'success', 'message' => 'Item has beed saved']);
}
public function update(Request $request, Customer $customer)
{
$request->validate([
'code' => 'required|string|max:255',
'name' => 'required|string|max:255',
'point' => 'required|numeric',
]);
$customer->update([
'code' => $request->code,
'name' => $request->name,
'last_point' => $request->point,
]);
return redirect()->route('customer.index')
->with('message', ['type' => 'success', 'message' => 'Item has beed updated']);
}
public function destroy(Customer $customer)
{
$customer->delete();
return redirect()->route('customer.index')
->with('message', ['type' => 'success', 'message' => 'Item has beed deleted']);
}
public function import()
{
}
}

@ -0,0 +1,24 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class CustomerPointController extends Controller
{
public function index()
{
}
public function store()
{
}
public function update()
{
}
public function destroy()
{
}
public function import()
{
}
}

@ -0,0 +1,23 @@
<?php
namespace App\Http\Controllers;
use App\Models\Setting;
use Illuminate\Http\Request;
class HomeController extends Controller
{
public function index()
{
return inertia('Home', [
'app_name' => Setting::where('key', 'app_name')->value('value'),
]);
}
public function check(Request $request)
{
$request->validate([
'customer_code' => 'required|string|exists:customers,code'
]);
}
}

@ -0,0 +1,41 @@
<?php
namespace App\Http\Controllers;
use App\Models\Setting;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class SettingController extends Controller
{
public function index()
{
return inertia('Setting/Index', [
'setting' => Setting::all(),
]);
}
public function update(Request $request)
{
$request->validate([
'app_name' => 'required|string',
]);
DB::beginTransaction();
foreach ($request->input() as $key => $value) {
Setting::updateOrCreate(
['key' => $key],
[
'value' => $value,
'type' => 'text'
]
);
}
DB::commit();
return redirect()->route('setting.index')
->with('message', ['type' => 'success', 'message' => 'Setting saved']);
}
}

@ -36,6 +36,7 @@ class HandleInertiaRequests extends Middleware
'flash' => [
'message' => fn () => $request->session()->get('message'),
],
'app_name' => env('APP_NAME', 'App Name')
]);
}
}

@ -2,10 +2,13 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Customer extends Model
{
use HasFactory;
protected $fillable = [
'name',
'code',
'start_point',
'last_point',
];
}

@ -2,10 +2,11 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class CustomerPoint extends Model
{
use HasFactory;
protected $fillable = [
'customer_id',
'description',
'point',
];
}

@ -12,8 +12,16 @@ return new class extends Migration
public function up(): void
{
Schema::create('customers', function (Blueprint $table) {
$table->id();
$table->ulid('id')->primary();
$table->string('name');
$table->string('code');
$table->decimal('start_point', 20, 2);
$table->decimal('last_point', 20, 2);
$table->timestamps();
$table->softDeletes();
$table->ulid('created_by')->nullable();
$table->ulid('updated_by')->nullable();
$table->ulid('deleted_by')->nullable();
});
}

@ -12,8 +12,15 @@ return new class extends Migration
public function up(): void
{
Schema::create('customer_points', function (Blueprint $table) {
$table->id();
$table->ulid('id')->primary();
$table->ulid('customer_id');
$table->string('description', 1000);
$table->decimal('point', 20, 2);
$table->timestamps();
$table->softDeletes();
$table->ulid('created_by')->nullable();
$table->ulid('updated_by')->nullable();
$table->ulid('deleted_by')->nullable();
});
}

@ -2,7 +2,9 @@
namespace Database\Seeders;
use App\Models\Setting;
use Illuminate\Database\Seeder;
use Illuminate\Support\Str;
class DummySeeder extends Seeder
{
@ -13,6 +15,10 @@ class DummySeeder extends Seeder
*/
public function run()
{
//
$settings = [
['id' => Str::ulid(), 'key' => 'app_name', 'value' => 'Customer Point', 'type' => 'text']
];
Setting::insert($settings);
}
}

@ -30,6 +30,18 @@ class PermissionSeeder extends Seeder
['id' => Str::ulid(), 'label' => 'Update Role', 'name' => 'update-role'],
['id' => Str::ulid(), 'label' => 'View Role', 'name' => 'view-role'],
['id' => Str::ulid(), 'label' => 'Delete Role', 'name' => 'delete-role'],
['id' => Str::ulid(), 'label' => 'View Setting', 'name' => 'view-setting'],
['id' => Str::ulid(), 'label' => 'Create Customer', 'name' => 'create-customer'],
['id' => Str::ulid(), 'label' => 'Update Customer', 'name' => 'update-customer'],
['id' => Str::ulid(), 'label' => 'View Customer', 'name' => 'view-customer'],
['id' => Str::ulid(), 'label' => 'Delete Customer', 'name' => 'delete-customer'],
['id' => Str::ulid(), 'label' => 'Create Customer Point', 'name' => 'create-customer-point'],
['id' => Str::ulid(), 'label' => 'Update Customer Point', 'name' => 'update-customer-point'],
['id' => Str::ulid(), 'label' => 'View Customer Point', 'name' => 'view-customer-point'],
['id' => Str::ulid(), 'label' => 'Delete Customer Point', 'name' => 'delete-customer-point'],
];
foreach ($permissions as $permission) {

@ -1,7 +1,10 @@
import React from 'react';
import { usePage } from '@inertiajs/react'
import React from 'react'
export default function ApplicationLogo({ className }) {
return (
<h1 className={className}>App Name</h1>
);
const {
props: { app_name },
} = usePage()
return <h1 className={className}>{app_name}</h1>
}

@ -1,11 +1,31 @@
import React from "react";
import Input from "./Input";
import React from 'react'
import Input from './Input'
export default function FormInput({ type, name, onChange, value, label, className, error, autoComplete, autoFocus, placeholder, disabled, readOnly}) {
export default function FormInput({
type,
name,
onChange,
value,
label,
className,
error,
autoComplete,
autoFocus,
placeholder,
disabled,
readOnly,
}) {
const id = `${name}-${label}`
return (
<div className={className}>
<label htmlFor="first_name" className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">{label}</label>
<label
htmlFor={id}
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
>
{label}
</label>
<Input
id={id}
type={type}
name={name}
onChange={onChange}
@ -19,4 +39,4 @@ export default function FormInput({ type, name, onChange, value, label, classNam
/>
</div>
)
}
}

@ -1,24 +1,43 @@
import React from 'react'
export default function Input({ type = 'text', name, onChange, value, error = "", autoComplete = false, autoFocus = false, placeholder , className ,disabled, readOnly}) {
export default function Input({
type = 'text',
name,
onChange,
value,
error = '',
autoComplete = false,
autoFocus = false,
placeholder,
className,
disabled,
readOnly,
id,
}) {
return (
<>
<input
<input
id={id}
type={type}
className={`mb-2 bg-gray-50 border text-gray-900 text-sm rounded-lg block w-full p-2.5 dark:bg-gray-700 dark:placeholder-gray-400 dark:text-white ${error ? "border-red-500 dark:border-red-500 focus:ring-red-500 focus:border-red-500 dark:focus:ring-red-500 dark:focus:border-red-500" : "border-gray-300 dark:border-gray-600 focus:ring-blue-500 focus:border-blue-500 dark:focus:ring-blue-500 dark:focus:border-blue-500"} ${className}`}
onChange={onChange}
className={`mb-2 bg-gray-50 border text-gray-900 text-sm rounded-lg block w-full p-2.5 dark:bg-gray-700 dark:placeholder-gray-400 dark:text-white ${
error
? 'border-red-500 dark:border-red-500 focus:ring-red-500 focus:border-red-500 dark:focus:ring-red-500 dark:focus:border-red-500'
: 'border-gray-300 dark:border-gray-600 focus:ring-blue-500 focus:border-blue-500 dark:focus:ring-blue-500 dark:focus:border-blue-500'
} ${className}`}
onChange={onChange}
name={name}
value={value}
autoComplete={autoComplete ? "on" : "off"}
autoComplete={autoComplete ? 'on' : 'off'}
autoFocus={autoFocus}
placeholder={placeholder}
disabled={disabled}
readOnly={readOnly}
/>
{error && (
<p className="mb-2 text-sm text-red-600 dark:text-red-500">{error}</p>
<p className="mb-2 text-sm text-red-600 dark:text-red-500">
{error}
</p>
)}
</>
)
}
}

@ -1,21 +1,24 @@
import React from 'react';
import { router } from '@inertiajs/react';
import { Sidebar } from 'flowbite-react';
import { HiLogout } from 'react-icons/hi';
import { filterOpenMenu } from './helpers';
import routes from './routes';
import { formatDate } from '@/utils';
import React from 'react'
import { Link, router, usePage } from '@inertiajs/react'
import { Sidebar } from 'flowbite-react'
import { HiLogout } from 'react-icons/hi'
import { filterOpenMenu } from './helpers'
import routes from './routes'
export default function SidebarNav({ user }) {
const menus = routes.filter(item => {
const {
props: { app_name },
} = usePage()
const menus = routes.filter((item) => {
item.open = false
if (!item.show) {
return null
}
if (+user.is_superadmin === 1) {
if (user.role === null) {
return filterOpenMenu(user, item)
}
if(user.role.permissions.find(p => p.name === item.permission)) {
if (user.role.permissions.find((p) => p.name === item.permission)) {
return item
}
@ -26,33 +29,36 @@ export default function SidebarNav({ user }) {
<Sidebar aria-label="Sidebar with multi-level dropdown example">
<Sidebar.Items>
<Sidebar.ItemGroup>
{menus.map(item => (
{menus.map((item) => (
<div key={item.name}>
{item.items === undefined ? (
<Sidebar.Item
onClick={() => router.visit(item.route)}
icon={item.icon}
active={route().current(item.active)}
>
{item.name}
</Sidebar.Item>
<Sidebar.Item
onClick={() => router.visit(item.route)}
icon={item.icon}
active={route().current(item.active)}
>
{item.name}
</Sidebar.Item>
) : (
<Sidebar.Collapse
icon={item.icon}
label={item.name}
open={item.open}
>
{item.items.map(item => (
<Sidebar.Item
{item.items.map((item) => (
<Sidebar.Item
key={item.name}
onClick={() => router.visit(item.route)}
icon={item.icon}
active={route().current(item.active)}
active={route().current(
item.active
)}
onClick={() =>
router.visit(item.route)
}
>
{item.name}
</Sidebar.Item>
))}
</Sidebar.Collapse>
)}
</div>
@ -64,10 +70,10 @@ export default function SidebarNav({ user }) {
Logout
</Sidebar.Item>
</Sidebar.ItemGroup>
<p className='text-sm font-light text-gray-900 dark:text-gray-100 text-center bottom-4 left-4 pt-10'>
App Name &copy; {(new Date()).getFullYear()}
<p className="text-sm font-light text-gray-900 dark:text-gray-100 text-center bottom-4 left-4 pt-10">
{app_name} &copy; {new Date().getFullYear()}
</p>
</Sidebar.Items>
</Sidebar>
)
}
}

@ -1,21 +1,25 @@
export const filterOpenMenu = (user, item) => {
const isAdmin = +user.is_superadmin === 1
const isAdmin = user.role === null
if ('items' in item) {
let items = []
if (isAdmin) {
items = item.items
} else {
items = item.items.filter(item => user.role.permissions.find(p => p.name === item.permission) ? item : null)
items = item.items.filter((item) =>
user.role.permissions.find((p) => p.name === item.permission)
? item
: null
)
}
if (items.length > 0) {
let activeItem = items.map(item => route().current(item.active))
let activeItem = items.map((item) => route().current(item.active))
item.open = activeItem.includes(true)
item.items = items.filter(item => item.show ? item : null)
item.items = items.filter((item) => (item.show ? item : null))
return item
}
}
if (isAdmin) {
return item
}
}
}

@ -1,56 +1,67 @@
import {
HiChartPie,
HiUser,
HiCollection,
HiAdjustments,
HiPlusCircle,
HiCurrencyDollar,
HiCash,
HiClipboardList,
HiHashtag,
HiUsers,
HiUserGroup,
HiUserCircle,
HiOutlineTruck,
HiDatabase,
HiShoppingBag,
HiReceiptTax,
HiHome,
HiInboxIn,
HiOutlineCash,
HiOutlineTable
} from "react-icons/hi";
HiCog,
} from 'react-icons/hi'
import { HiTrophy } from 'react-icons/hi2'
export default [
{
name: "Dashboard",
name: 'Dashboard',
show: true,
icon: HiChartPie,
route: route("dashboard"),
active: "dashboard",
permission: "view-dashboard",
route: route('dashboard'),
active: 'dashboard',
permission: 'view-dashboard',
},
{
name: "User",
name: 'Customers',
show: true,
icon: HiUserCircle,
route: route('customer.index'),
active: 'customer.index',
permission: 'view-customer',
},
{
name: 'Point',
show: true,
icon: HiTrophy,
route: route('customer-point.index'),
active: 'customer-point.index',
permission: 'view-customer-point',
},
{
name: 'Admin',
show: true,
icon: HiUser,
items: [
{
name: "Roles",
name: 'Roles',
show: true,
icon: HiUserGroup,
route: route("roles.index"),
active: "roles.*",
permission: "view-role",
route: route('roles.index'),
active: 'roles.*',
permission: 'view-role',
},
{
name: "Users",
name: 'Users',
show: true,
icon: HiUsers,
route: route("user.index"),
active: "user.index",
permission: "view-user",
route: route('user.index'),
active: 'user.index',
permission: 'view-user',
},
],
},
];
{
name: 'Setting',
show: true,
icon: HiCog,
route: route('setting.index'),
active: 'setting.index',
permission: 'view-setting',
},
]

@ -0,0 +1,102 @@
import React, { useEffect } from 'react'
import Modal from '@/Components/Modal'
import { useForm } from '@inertiajs/react'
import Button from '@/Components/Button'
import FormInput from '@/Components/FormInput'
import { isEmpty } from 'lodash'
export default function FormModal(props) {
const { modalState } = props
const { data, setData, post, put, processing, errors, reset, clearErrors } =
useForm({
code: '',
name: '',
point: 0,
})
const handleOnChange = (event) => {
setData(
event.target.name,
event.target.type === 'checkbox'
? event.target.checked
? 1
: 0
: event.target.value
)
}
const handleReset = () => {
modalState.setData(null)
reset()
clearErrors()
}
const handleClose = () => {
handleReset()
modalState.toggle()
}
const handleSubmit = () => {
const customer = modalState.data
if (customer !== null) {
put(route('customer.update', customer), {
onSuccess: () => handleClose(),
})
return
}
post(route('customer.store'), {
onSuccess: () => handleClose(),
})
}
useEffect(() => {
const customer = modalState.data
if (isEmpty(customer) === false) {
setData({
name: customer.name,
code: customer.code,
point: customer.last_point,
})
return
}
}, [modalState])
return (
<Modal
isOpen={modalState.isOpen}
toggle={handleClose}
title={'Customer'}
>
<FormInput
name="code"
value={data.code}
onChange={handleOnChange}
label="Code"
error={errors.code}
/>
<FormInput
name="name"
value={data.name}
onChange={handleOnChange}
label="Name"
error={errors.name}
/>
<FormInput
type="number"
name="point"
value={data.point}
onChange={handleOnChange}
label="Point"
error={errors.point}
/>
<div className="flex items-center">
<Button onClick={handleSubmit} processing={processing}>
Simpan
</Button>
<Button onClick={handleClose} type="secondary">
Batal
</Button>
</div>
</Modal>
)
}

@ -0,0 +1,196 @@
import React, { useEffect, useState } from 'react'
import { 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 FormModal from './FormModal'
import SearchInput from '@/Components/SearchInput'
import { hasPermission } from '@/utils'
export default function Customer(props) {
const {
query: { links, data },
auth,
} = props
const [search, setSearch] = useState('')
const preValue = usePrevious(search)
const confirmModal = useModalState()
const formModal = useModalState()
const toggleFormModal = (customer = null) => {
formModal.setData(customer)
formModal.toggle()
}
const handleDeleteClick = (customer) => {
confirmModal.setData(customer)
confirmModal.toggle()
}
const onDelete = () => {
if (confirmModal.data !== null) {
router.delete(route('customer.destroy', confirmModal.data.id))
}
}
const params = { q: search }
useEffect(() => {
if (preValue) {
router.get(
route(route().current()),
{ q: search },
{
replace: true,
preserveState: true,
}
)
}
}, [search])
const canCreate = hasPermission(auth, 'create-customer')
const canUpdate = hasPermission(auth, 'update-customer')
const canDelete = hasPermission(auth, 'delete-customer')
return (
<AuthenticatedLayout
auth={props.auth}
errors={props.errors}
flash={props.flash}
page={'Customer'}
action={'List'}
>
<Head title="Customer" />
<div>
<div className="mx-auto sm:px-6 lg:px-8 ">
<div className="p-6 overflow-hidden shadow-sm sm:rounded-lg bg-gray-200 dark:bg-gray-800 space-y-4">
<div className="flex justify-between">
{canCreate && (
<Button
size="sm"
onClick={() => toggleFormModal()}
>
Create
</Button>
)}
<div className="flex items-center">
<SearchInput
onChange={(e) => setSearch(e.target.value)}
value={search}
/>
</div>
</div>
<div className="overflow-auto">
<div>
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400 mb-4">
<thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
<tr>
<th
scope="col"
className="py-3 px-6"
>
Code
</th>
<th
scope="col"
className="py-3 px-6"
>
Name
</th>
<th
scope="col"
className="py-3 px-6"
>
Point
</th>
<th
scope="col"
className="py-3 px-6"
/>
</tr>
</thead>
<tbody>
{data.map((customer) => (
<tr
className="bg-white border-b dark:bg-gray-800 dark:border-gray-700"
key={customer.id}
>
<td
scope="row"
className="py-4 px-6 font-medium text-gray-900 whitespace-nowrap dark:text-white"
>
{customer.code}
</td>
<td className="py-4 px-6">
{customer.name}
</td>
<td className="py-4 px-6">
{customer.last_point}
</td>
<td className="py-4 px-6 flex justify-end">
<Dropdown
label={'Opsi'}
floatingArrow={true}
arrowIcon={true}
dismissOnClick={true}
size={'sm'}
>
{canUpdate && (
<Dropdown.Item
onClick={() =>
toggleFormModal(
customer
)
}
>
<div className="flex space-x-1 items-center">
<HiPencil />
<div>
Edit
</div>
</div>
</Dropdown.Item>
)}
{canDelete && (
<Dropdown.Item
onClick={() =>
handleDeleteClick(
customer
)
}
>
<div className="flex space-x-1 items-center">
<HiTrash />
<div>
Delete
</div>
</div>
</Dropdown.Item>
)}
</Dropdown>
</td>
</tr>
))}
</tbody>
</table>
</div>
<div className="w-full flex items-center justify-center">
<Pagination links={links} params={params} />
</div>
</div>
</div>
</div>
</div>
<ModalConfirm modalState={confirmModal} onConfirm={onDelete} />
<FormModal modalState={formModal} />
</AuthenticatedLayout>
)
}

@ -0,0 +1,263 @@
import React, { useRef, useEffect, useState } from 'react'
import { useDebounce } from '@/hooks'
import { usePage } from '@inertiajs/react'
import axios from 'axios'
import { HiChevronDown, HiChevronUp, HiX } from 'react-icons/hi'
import { Spinner } from 'flowbite-react'
export default function SelectionInput(props) {
const ref = useRef()
const {
props: { auth },
} = usePage()
const {
label = '',
itemSelected = null,
onItemSelected = () => {},
disabled = false,
placeholder = '',
error = '',
all = 0,
} = props
const [showItems, setShowItem] = useState([])
const [isSelected, setIsSelected] = useState(true)
const [selected, setSelected] = useState(null)
const [query, setQuery] = useState('')
const q = useDebounce(query, 300)
const [isOpen, setIsOpen] = useState(false)
const [loading, setLoading] = useState(false)
const toggle = () => {
setQuery('')
setIsOpen(!isOpen)
}
const onInputMouseDown = () => {
setIsSelected(false)
setQuery('')
setIsOpen(!isOpen)
}
const handleSelectItem = (item) => {
setIsSelected(true)
onItemSelected(item.id)
setSelected(item.name)
setIsOpen(false)
}
const removeItem = () => {
setIsSelected(false)
setSelected('')
onItemSelected(null)
}
const filterItems = (value) => {
setIsSelected(false)
setQuery(value)
}
useEffect(() => {
if (isOpen === true) {
const checkIfClickedOutside = (e) => {
if (isOpen && ref.current && !ref.current.contains(e.target)) {
setIsOpen(false)
if (selected !== null) {
setIsSelected(true)
}
}
}
document.addEventListener('mousedown', checkIfClickedOutside)
return () => {
document.removeEventListener('mousedown', checkIfClickedOutside)
}
}
}, [isOpen])
const fetch = (q = '') => {
setLoading(true)
axios
.get(route('api.customer.index', { q: q, all: all }), {
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + auth.user.jwt_token,
},
})
.then((response) => {
setShowItem(response.data)
})
.catch((err) => {
alert(err)
})
.finally(() => setLoading(false))
}
// every select item open
useEffect(() => {
if (isOpen) {
fetch(q)
}
}, [q, isOpen])
// once page load
useEffect(() => {
fetch()
}, [])
useEffect(() => {
if (disabled) {
setSelected('')
}
}, [disabled])
useEffect(() => {
if (itemSelected !== null) {
const item = showItems.find((item) => item.id === itemSelected)
if (item) {
setSelected(item.name)
setIsSelected(true)
}
return
}
setIsSelected(false)
}, [itemSelected, loading])
useEffect(() => {
if (isSelected && selected === '') {
setSelected('')
setIsSelected(false)
}
}, [isSelected])
return (
<div className="flex flex-col items-center" ref={ref}>
<div className="w-full flex flex-col items-center">
<div className="w-full">
<div className="flex flex-col relative">
{label !== '' && (
<label
htmlFor="first_name"
className="mb-2 block text-sm font-medium text-gray-900 dark:text-white"
>
{label}
</label>
)}
<div className="w-full">
<div
className={`p-1.5 mb-2 bg-gray-50 dark:bg-gray-700 flex border rounded-lg
${
error
? 'border-red-500'
: 'border-gray-300 dark:border-gray-600'
}
${disabled ? 'bg-gray-50' : ''}`}
>
<input
className="block w-full text-sm bg-gray-50 text-gray-900 dark:border-gray-700 border cursor-pointer dark:text-gray-300 outline-none border-transparent dark:bg-gray-700 dark:placeholder-gray-400 px-1"
onMouseDown={onInputMouseDown}
placeholder={placeholder}
value={`${
isSelected
? selected === null
? ''
: selected
: query
}`}
onChange={(e) =>
filterItems(e.target.value)
}
disabled={disabled}
/>
{isSelected && (
<div
onClick={
disabled ? () => {} : removeItem
}
>
<button className="cursor-pointer w-6 h-6 text-red-300 outline-none focus:outline-none">
<HiX />
</button>
</div>
)}
<div onClick={disabled ? () => {} : toggle}>
<button className="cursor-pointer w-6 h-6 text-gray-300 outline-none focus:outline-none">
{isOpen ? (
<HiChevronUp />
) : (
<HiChevronDown />
)}
</button>
</div>
</div>
{error && (
<p className="mb-2 text-sm text-red-600 dark:text-red-500">
{error}
</p>
)}
</div>
{isOpen && (
<div
className="absolute mt-1 shadow-lg bg-gray-50 dark:bg-gray-700 dark:text-gray-200 top-100 z-40 w-full lef-0 rounded overflow-y-auto"
style={{ maxHeight: '300px', top: '100%' }}
>
<div className="flex flex-col w-full">
{loading ? (
<div>
<div className="flex w-full items-center p-2 pl-2 border-transparent border-l-2 relative hover:border-neutral-content">
<div className="w-full items-center justify-center flex">
<div className="mx-2 my-5">
<Spinner className="mr-2" />
<span>Loading...</span>
</div>
</div>
</div>
</div>
) : (
<>
{showItems.map((item, index) => (
<div
key={index}
onClick={() =>
handleSelectItem(item)
}
>
<div className="flex w-full items-center p-2 pl-2 border-transparent border-l-2 relative hover:border-neutral-content hover:bg-gray-400 bg-opacity-10 dark:hover:bg-gray-200 dark:hover:bg-opacity-10 dark:hover:text-gray-100">
<div className="w-full items-center flex">
<div className="mx-2">
<span>
{item.name}
</span>
</div>
</div>
</div>
</div>
))}
{showItems.length <= 0 && (
<div>
<div className="flex w-full items-center p-2 pl-2 border-transparent border-l-2 relative hover:border-neutral-content">
<div className="w-full items-center justify-center flex">
<div className="mx-2 my-5">
<span>
No Items
Found
</span>
</div>
</div>
</div>
</div>
)}
</>
)}
</div>
</div>
)}
</div>
</div>
</div>
</div>
)
}

@ -0,0 +1,69 @@
import React, { useEffect } from 'react'
import GuestLayout from '@/Layouts/GuestLayout'
import InputError from '@/Components/Defaults/InputError'
import { Head, Link, useForm } from '@inertiajs/react'
import { Button, TextInput, Label, Checkbox, Spinner } from 'flowbite-react'
export default function Login({ app_name }) {
const { data, setData, post, processing, errors, reset } = useForm({
customer_code: '',
})
const onHandleChange = (event) => {
setData(
event.target.name,
event.target.type === 'checkbox'
? event.target.checked
: event.target.value
)
}
const handleKeyDown = (e) => {
if (e.code === 'Enter') {
post(route('home'))
}
}
const submit = (e) => {
e.preventDefault()
post(route('home'))
}
return (
<div className="min-h-screen flex flex-col sm:justify-center items-center pt-6 sm:pt-0 bg-gray-100 dark:bg-gray-900">
<Head title="Check Point" />
<div className="w-full max-w-md mt-6 px-6 py-4 bg-white dark:bg-gray-800 shadow-md overflow-hidden sm:rounded-lg">
<div className="w-full text-center mt-5 mb-10 h-20 fill-current text-gray-500 text-5xl font-bold">
{app_name}
</div>
<form onSubmit={submit}>
<div>
<TextInput
type="text"
name="customer_code"
value={data.customer_code}
className="mt-1 block w-full"
autoFocus={true}
onChange={onHandleChange}
placeholder="Customer Code"
onKeyDown={handleKeyDown}
/>
<InputError
message={errors.customer_code}
className="mt-2"
/>
</div>
<div className="flex items-center justify-end mt-4">
<Button onClick={submit} disabled={processing}>
{processing ? <Spinner /> : 'Check'}
</Button>
</div>
</form>
</div>
</div>
)
}

@ -0,0 +1,76 @@
import React from 'react'
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout'
import FormInput from '@/Components/FormInput'
import Button from '@/Components/Button'
import { Head, useForm } from '@inertiajs/react'
import TextArea from '@/Components/TextArea'
import { isEmpty } from 'lodash'
const extractValue = (set, key) => {
const find = set.find((s) => s.key === key)
if (isEmpty(find) === false) {
if (find.type === 'image') {
return find?.url
}
return find?.value
}
return ''
}
export default function Setting(props) {
const { setting } = props
const { data, setData, post, processing, errors } = useForm({
app_name: extractValue(setting, 'app_name'),
})
const handleOnChange = (event) => {
setData(
event.target.name,
event.target.type === 'checkbox'
? event.target.checked
? 1
: 0
: event.target.value
)
}
const handleSubmit = () => {
post(route('setting.update'))
}
return (
<AuthenticatedLayout
auth={props.auth}
errors={props.errors}
flash={props.flash}
page={'Setting'}
action={''}
>
<Head title="Setting" />
<div>
<div className="mx-auto sm:px-6 lg:px-8">
<div className="overflow-hidden p-4 shadow-sm sm:rounded-lg bg-white dark:bg-gray-800 flex flex-col">
<div className="text-xl font-bold mb-4">Setting</div>
<FormInput
name="app_name"
value={data.app_name}
onChange={handleOnChange}
label="App Name"
error={errors.app_name}
/>
<div className="mt-2">
<Button
onClick={handleSubmit}
processing={processing}
>
Simpan
</Button>
</div>
</div>
</div>
</div>
</AuthenticatedLayout>
)
}

@ -1,6 +1,7 @@
<?php
use App\Http\Controllers\Api\RoleController;
use App\Http\Controllers\Api\CustomerController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
@ -19,4 +20,5 @@ Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
Route::get('/customers', [CustomerController::class, 'index'])->name('api.customer.index');
Route::get('/roles', [RoleController::class, 'index'])->name('api.role.index');

@ -1,9 +1,13 @@
<?php
use App\Http\Controllers\CustomerController;
use App\Http\Controllers\CustomerPointController;
use App\Http\Controllers\GeneralController;
use App\Http\Controllers\HomeController;
use App\Http\Controllers\ProfileController;
use App\Http\Controllers\RoleController;
use App\Http\Controllers\UserController;
use App\Http\Controllers\SettingController;
use Illuminate\Support\Facades\Route;
/*
@ -17,9 +21,8 @@ use Illuminate\Support\Facades\Route;
|
*/
Route::get('/', function () {
return redirect()->route('login');
});
Route::get('/', [HomeController::class, 'index'])->name('home');
Route::post('/', [HomeController::class, 'check']);
Route::middleware(['auth'])->group(function () {
Route::get('/dashboard', [GeneralController::class, 'index'])->name('dashboard');
@ -33,6 +36,24 @@ Route::middleware(['auth'])->group(function () {
// Role
Route::resource('/roles', RoleController::class);
// Setting
Route::get('/setting', [SettingController::class, 'index'])->name('setting.index');
Route::post('/setting', [SettingController::class, 'update'])->name('setting.update');
// Customer
Route::get('/customers', [CustomerController::class, 'index'])->name('customer.index');
Route::post('/customers/import', [CustomerController::class, 'import'])->name('customer.import');
Route::post('/customers', [CustomerController::class, 'store'])->name('customer.store');
Route::put('/customers/{customer}', [CustomerController::class, 'update'])->name('customer.update');
Route::delete('/customers/{customer}', [CustomerController::class, 'destroy'])->name('customer.destroy');
// Customer Point
Route::get('/customers-points', [CustomerPointController::class, 'index'])->name('customer-point.index');
Route::post('/customers-points/import', [CustomerPointController::class, 'import'])->name('customer-point.import');
Route::post('/customers-points', [CustomerPointController::class, 'store'])->name('customer-point.store');
Route::put('/customers-points/{customer}', [CustomerPointController::class, 'update'])->name('customer-point.update');
Route::delete('/customers-points/{customer}', [CustomerPointController::class, 'destroy'])->name('customer-point.destroy');
});
Route::middleware('auth')->group(function () {
@ -41,4 +62,4 @@ Route::middleware('auth')->group(function () {
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
});
require __DIR__.'/auth.php';
require __DIR__ . '/auth.php';

Loading…
Cancel
Save