dev
Aji Kamaludin 1 year ago
parent b8124181f8
commit 165bd9ee86
No known key found for this signature in database
GPG Key ID: 19058F67F0083AD3

@ -3,6 +3,7 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Models\Customer; use App\Models\Customer;
use App\Services\GeneralService;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Str; use Illuminate\Support\Str;
@ -17,7 +18,7 @@ class CustomerController extends Controller
} }
$query->orderBy('created_at', 'desc'); $query->orderBy('created_at', 'desc');
return inertia('Customer/Index', [ return inertia('Customer/Index', [
'query' => $query->paginate(10), 'query' => $query->paginate(10),
]); ]);
@ -32,7 +33,7 @@ class CustomerController extends Controller
]); ]);
Customer::create([ Customer::create([
'code' => Str::upper(Str::random(6)), 'code' => 'PE-' . GeneralService::formatNum(Customer::count() + 1),
'name' => $request->name, 'name' => $request->name,
'phone' => $request->phone, 'phone' => $request->phone,
'address' => $request->address, 'address' => $request->address,

@ -3,6 +3,7 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Models\Product; use App\Models\Product;
use App\Services\GeneralService;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Str; use Illuminate\Support\Str;
@ -17,7 +18,7 @@ class ProductController extends Controller
} }
$query->orderBy('created_at', 'desc'); $query->orderBy('created_at', 'desc');
return inertia('Product/Index', [ return inertia('Product/Index', [
'query' => $query->paginate(10), 'query' => $query->paginate(10),
]); ]);
@ -31,15 +32,17 @@ class ProductController extends Controller
'cost' => 'required|numeric|min:1', 'cost' => 'required|numeric|min:1',
'stock' => 'required|numeric|min:1', 'stock' => 'required|numeric|min:1',
'category_id' => 'required|exists:categories,id', 'category_id' => 'required|exists:categories,id',
'is_active' => 'required|in:0,1',
]); ]);
Product::create([ Product::create([
'code' => Str::upper(Str::random(6)), 'code' => 'PO-' . GeneralService::formatNum(Product::count() + 1),
'name' => $request->name, 'name' => $request->name,
'price' => $request->price, 'price' => $request->price,
'cost' => $request->cost, 'cost' => $request->cost,
'stock' => $request->stock, 'stock' => $request->stock,
'category_id' => $request->category_id, 'category_id' => $request->category_id,
'is_active' => $request->is_active,
]); ]);
return redirect()->route('product.index') return redirect()->route('product.index')
@ -54,6 +57,7 @@ class ProductController extends Controller
'cost' => 'required|numeric|min:1', 'cost' => 'required|numeric|min:1',
'stock' => 'required|numeric|min:1', 'stock' => 'required|numeric|min:1',
'category_id' => 'required|exists:categories,id', 'category_id' => 'required|exists:categories,id',
'is_active' => 'required|in:0,1',
]); ]);
$product->update([ $product->update([
@ -62,6 +66,7 @@ class ProductController extends Controller
'cost' => $request->cost, 'cost' => $request->cost,
'stock' => $request->stock, 'stock' => $request->stock,
'category_id' => $request->category_id, 'category_id' => $request->category_id,
'is_active' => $request->is_active,
]); ]);
return redirect()->route('product.index') return redirect()->route('product.index')

@ -4,6 +4,10 @@ namespace App\Models;
class Product extends Model class Product extends Model
{ {
const ACTIVE = 0;
const INACTIVE = 1;
protected $fillable = [ protected $fillable = [
'code', 'code',
'name', 'name',
@ -11,6 +15,7 @@ class Product extends Model
'cost', 'cost',
'stock', 'stock',
'category_id', 'category_id',
'is_active'
]; ];
public function category() public function category()

@ -0,0 +1,24 @@
<?php
namespace App\Services;
class GeneralService
{
public static function formatNum($num)
{
// 0001
if ($num < 10) {
return '000' . $num;
}
if ($num < 100) {
return '00' . $num;
}
if ($num < 1000) {
return '0' . $num;
}
return $num;
}
}

@ -19,6 +19,7 @@ return new class extends Migration
$table->decimal('cost', 14, 2)->default(0); $table->decimal('cost', 14, 2)->default(0);
$table->decimal('stock', 14, 2)->default(0); $table->decimal('stock', 14, 2)->default(0);
$table->uuid('category_id')->nullable(); $table->uuid('category_id')->nullable();
$table->smallInteger('is_active')->default(0);
$table->timestamps(); $table->timestamps();
$table->softDeletes(); $table->softDeletes();
$table->uuid('created_by')->nullable(); $table->uuid('created_by')->nullable();

@ -5,6 +5,7 @@ namespace Database\Seeders;
use App\Models\Category; use App\Models\Category;
use App\Models\Customer; use App\Models\Customer;
use App\Models\Product; use App\Models\Product;
use App\Services\GeneralService;
use Illuminate\Database\Seeder; use Illuminate\Database\Seeder;
use Illuminate\Support\Str; use Illuminate\Support\Str;
@ -48,9 +49,9 @@ class DummySeeder extends Seeder
'Sepatu', 'Sepatu',
'Obat Nyamuk' 'Obat Nyamuk'
]; ];
foreach ($products as $prod) { foreach ($products as $index => $prod) {
Product::create([ Product::create([
'code' => Str::upper(Str::random(6)), 'code' => 'PO-' . GeneralService::formatNum($index + 1),
'name' => $prod, 'name' => $prod,
'price' => rand(1000, 10000), 'price' => rand(1000, 10000),
'cost' => rand(1000, 10000), 'cost' => rand(1000, 10000),
@ -59,9 +60,9 @@ class DummySeeder extends Seeder
]); ]);
} }
foreach (['Customer A', 'Customer B'] as $cust) { foreach (['Customer A', 'Customer B'] as $index => $cust) {
Customer::create([ Customer::create([
'code' => Str::upper(Str::random(6)), 'code' => 'PE-' . GeneralService::formatNum($index + 1),
'name' => $cust, 'name' => $cust,
]); ]);
} }

@ -1,43 +1,52 @@
import React, { useEffect } from 'react'; import React, { useEffect } from 'react'
import GuestLayout from '@/Layouts/GuestLayout'; import GuestLayout from '@/Layouts/GuestLayout'
import InputError from '@/Components/Defaults/InputError'; import InputError from '@/Components/Defaults/InputError'
import { Head, Link, useForm } from '@inertiajs/react'; import { Head, Link, useForm } from '@inertiajs/react'
import { Button, TextInput,Label, Checkbox, Spinner } from 'flowbite-react'; import { Button, TextInput, Label, Checkbox, Spinner } from 'flowbite-react'
export default function Login({ status }) { export default function Login({ status }) {
const { data, setData, post, processing, errors, reset } = useForm({ const { data, setData, post, processing, errors, reset } = useForm({
email: '', email: '',
password: '', password: '',
remember: '', remember: '',
}); })
useEffect(() => { useEffect(() => {
return () => { return () => {
reset('password'); reset('password')
}; }
}, []); }, [])
const onHandleChange = (event) => { const onHandleChange = (event) => {
setData(event.target.name, event.target.type === 'checkbox' ? event.target.checked : event.target.value); setData(
}; event.target.name,
event.target.type === 'checkbox'
? event.target.checked
: event.target.value
)
}
const handleKeyDown = e => { const handleKeyDown = (e) => {
if(e.code === 'Enter') { if (e.code === 'Enter') {
post(route('login')) post(route('login'))
} }
} }
const submit = (e) => { const submit = (e) => {
e.preventDefault(); e.preventDefault()
post(route('login')); post(route('login'))
}; }
return ( return (
<GuestLayout> <GuestLayout>
<Head title="Log in" /> <Head title="Log in" />
{status && <div className="mb-4 font-medium text-sm text-green-600">{status}</div>} {status && (
<div className="mb-4 font-medium text-sm text-green-600">
{status}
</div>
)}
<form onSubmit={submit}> <form onSubmit={submit}>
<div> <div>
@ -66,29 +75,37 @@ export default function Login({ status }) {
className="mt-1 block w-full" className="mt-1 block w-full"
autoComplete="current-password" autoComplete="current-password"
onChange={onHandleChange} onChange={onHandleChange}
onKeyDownCapture={e => handleKeyDown(e)} onKeyDownCapture={(e) => handleKeyDown(e)}
/> />
<InputError message={errors.password} className="mt-2" /> <InputError message={errors.password} className="mt-2" />
</div> </div>
<div className="block mt-4"> <div className="flex flex-row justify-between items-center mt-4">
<label className="flex items-center space-x-2"> <div className="block ">
<Checkbox id="remember" value={data.remember} onChange={onHandleChange}/> <label className="flex items-center space-x-2">
<Label htmlFor="remember"> <Checkbox
Remember me id="remember"
</Label> value={data.remember}
</label> onChange={onHandleChange}
/>
<Label htmlFor="remember">Remember me</Label>
</label>
</div>
<Link
href={route('password.request')}
className="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
Forgot password
</Link>
</div> </div>
<div className="flex items-center justify-end mt-4"> <div className="flex items-center justify-end mt-4">
<Button onClick={submit} disabled={processing}> <Button onClick={submit} disabled={processing}>
{processing ? ( {processing ? <Spinner /> : 'Log in'}
<Spinner/>
) : ('Log in')}
</Button> </Button>
</div> </div>
</form> </form>
</GuestLayout> </GuestLayout>
); )
} }

@ -16,6 +16,7 @@ export default function FormModal(props) {
cost: 0, cost: 0,
stock: 0, stock: 0,
category_id: null, category_id: null,
is_active: 0,
}) })
const handleOnChange = (event) => { const handleOnChange = (event) => {
@ -62,6 +63,7 @@ export default function FormModal(props) {
cost: product.cost, cost: product.cost,
stock: product.stock, stock: product.stock,
category_id: product.category_id, category_id: product.category_id,
is_active: product.is_active,
}) })
return return
} }
@ -106,6 +108,23 @@ export default function FormModal(props) {
onItemSelected={(id) => setData('category_id', id)} onItemSelected={(id) => setData('category_id', id)}
error={errors.category_id} error={errors.category_id}
/> />
<div className="mt-4">
<div className="mb-1 text-sm">Status</div>
<select
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
onChange={handleOnChange}
value={data.is_active}
name="is_active"
>
<option value="0">Aktif</option>
<option value="1">Tidak Aktif</option>
</select>
{errors.is_active && (
<p className="mb-2 text-sm text-red-600 dark:text-red-500">
{errors.is_active}
</p>
)}
</div>
<div className="flex items-center"> <div className="flex items-center">
<Button onClick={handleSubmit} processing={processing}> <Button onClick={handleSubmit} processing={processing}>
Simpan Simpan

@ -105,6 +105,12 @@ export default function Product(props) {
> >
Nama Nama
</th> </th>
<th
scope="col"
className="py-3 px-6"
>
Status
</th>
<th <th
scope="col" scope="col"
className="py-3 px-6" className="py-3 px-6"
@ -150,6 +156,16 @@ export default function Product(props) {
<td className="py-4 px-6"> <td className="py-4 px-6">
{product.name} {product.name}
</td> </td>
<td className="py-4 px-6">
<div
className={`w-5 h-5 rounded-full mx-auto ${
+product.is_active ===
0
? 'bg-green-500'
: 'bg-red-500'
}`}
></div>
</td>
<td className="py-4 px-6"> <td className="py-4 px-6">
{product.category.name} {product.category.name}
</td> </td>

@ -105,8 +105,8 @@ export default function Sale(props) {
<Head title="Penjualan" /> <Head title="Penjualan" />
<div className="mx-auto sm:px-6 lg:px-8 w-full"> <div className="mx-auto sm:px-6 lg:px-8 w-full">
<div className="flex flex-row p-6 shadow-sm sm:rounded-lg bg-white w-full space-x-2"> <div className="flex flex-col lg:flex-row p-6 shadow-sm sm:rounded-lg bg-white w-full gap-2">
<div className="w-full md:w-7/12"> <div className="w-full lg:w-7/12">
<div className="mb-4"> <div className="mb-4">
<SearchInput <SearchInput
onChange={(e) => setSearch(e.target.value)} onChange={(e) => setSearch(e.target.value)}
@ -118,16 +118,19 @@ export default function Sale(props) {
<Spinner size="xl" /> <Spinner size="xl" />
</div> </div>
) : ( ) : (
<div className="grid grid-cols-4 gap-2 text-center h-[320px]"> <div className="grid grid-cols-2 lg:grid-cols-4 gap-2 text-center min-h-[320px]">
{products.map((item) => ( {products.map((item) => (
<div <div
className="rounded bg-gray-300 hover:bg-gray-200 shadow-lg px-4 py-2 flex flex-col justify-between" className="rounded bg-gray-200 hover:bg-gray-300 shadow-lg px-4 py-2 flex flex-col gap-1 justify-between"
key={item.id} key={item.id}
onClick={() => addItem(item)} onClick={() => addItem(item)}
> >
<div className="font-bold"> <div className="text-base">
{item.name} {item.name}
</div> </div>
<div className="font-bold">
({item.code})
</div>
<div className="rounded-md bg-gray-800 p-0.5 text-white"> <div className="rounded-md bg-gray-800 p-0.5 text-white">
Rp. {formatIDR(item.price)} Rp. {formatIDR(item.price)}
</div> </div>
@ -151,7 +154,7 @@ export default function Sale(props) {
/> />
</div> </div>
</div> </div>
<div className="w-full md:w-5/12 flex flex-col"> <div className="w-full lg:w-5/12 flex flex-col">
<CustomerSelectionInput <CustomerSelectionInput
placeholder="Pelanggan" placeholder="Pelanggan"
itemSelected={data.customer_id} itemSelected={data.customer_id}

Loading…
Cancel
Save