diff --git a/.env.example b/.env.example index 7ccfa9d..ae84bd3 100644 --- a/.env.example +++ b/.env.example @@ -58,3 +58,21 @@ VITE_PUSHER_SCHEME="${PUSHER_SCHEME}" VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" HTTPS_AWARE=false + +DS_APP_HOST=10.25.10.1 +DS_APP_PORT=9191 +DS_SEND_QUERIES=false +DS_SEND_HTTP_CLIENT_REQUESTS=false +DS_SEND_JOBS=false +DS_SEND_COMMANDS=false +DS_SEND_SCHEDULED_COMMANDS=false +DS_SEND_CACHE=false +DS_SEND_GATE=false +DS_SEND_LOGS=false +DS_SEND_LIVEWIRE_COMPONENTS=false +DS_LIVEWIRE_EVENTS=false +DS_LIVEWIRE_DISPATCH=false +DS_SEND_LIVEWIRE_FAILED_VALIDATION=false +DS_AUTO_CLEAR_ON_PAGE_RELOAD=false +DS_AUTO_INVOKE_APP=false +DS_PREFERRED_IDE=vscode \ No newline at end of file diff --git a/app/Http/Controllers/Api/CustomerController.php b/app/Http/Controllers/Api/CustomerController.php index b2f6bfe..c2efaf5 100644 --- a/app/Http/Controllers/Api/CustomerController.php +++ b/app/Http/Controllers/Api/CustomerController.php @@ -18,6 +18,6 @@ class CustomerController extends Controller ->orWhere('username', 'like', "%$request->q%"); } - return $query->get(); + return $query->limit(100)->get(); } } diff --git a/app/Http/Controllers/Api/LocationController.php b/app/Http/Controllers/Api/LocationController.php index 2dbbc89..2bfe7ce 100644 --- a/app/Http/Controllers/Api/LocationController.php +++ b/app/Http/Controllers/Api/LocationController.php @@ -16,6 +16,6 @@ class LocationController extends Controller $query->where('name', 'like', "%$request->q%"); } - return $query->get(); + return $query->limit(100)->get(); } } diff --git a/app/Http/Controllers/Api/LocationProfileController.php b/app/Http/Controllers/Api/LocationProfileController.php new file mode 100644 index 0000000..6846036 --- /dev/null +++ b/app/Http/Controllers/Api/LocationProfileController.php @@ -0,0 +1,23 @@ +orderBy('updated_at', 'desc'); + + if ($request->q != '') { + $query->where('name', 'like', "%$request->q%") + ->orWhere('display_note', 'like', "%$request->q%") + ->orWhereHas('location', fn ($q) => $q->where('name', 'like', "%$request->q%")); + } + + return $query->limit(100)->get(); + } +} diff --git a/app/Http/Controllers/Api/RoleController.php b/app/Http/Controllers/Api/RoleController.php index 94ed150..7f7ebe2 100644 --- a/app/Http/Controllers/Api/RoleController.php +++ b/app/Http/Controllers/Api/RoleController.php @@ -16,6 +16,6 @@ class RoleController extends Controller $query->where('name', 'like', "%{$request->q}%"); } - return $query->get(); + return $query->limit(100)->get(); } } diff --git a/app/Http/Controllers/LocationController.php b/app/Http/Controllers/LocationController.php index af857cb..4822d42 100644 --- a/app/Http/Controllers/LocationController.php +++ b/app/Http/Controllers/LocationController.php @@ -7,10 +7,14 @@ use Illuminate\Http\Request; class LocationController extends Controller { - public function index() + public function index(Request $request) { $query = Location::orderBy('updated_at', 'desc'); + if ($request->q != '') { + $query->where('name', 'like', "%$request->q%"); + } + return inertia('Location/Index', [ 'query' => $query->paginate(), ]); diff --git a/app/Http/Controllers/LocationProfileController.php b/app/Http/Controllers/LocationProfileController.php index 545211e..a1828ba 100644 --- a/app/Http/Controllers/LocationProfileController.php +++ b/app/Http/Controllers/LocationProfileController.php @@ -97,7 +97,7 @@ class LocationProfileController extends Controller return inertia('LocationProfile/Form', [ 'expireds' => LocationProfile::EXPIRED_UNIT, 'levels' => CustomerLevel::all(), - 'profile' => $profile->load(['location', 'prices.level']) + 'profile' => $profile->load(['location', 'prices.level']), ]); } diff --git a/app/Http/Controllers/VoucherController.php b/app/Http/Controllers/VoucherController.php index 1150822..1ff28b1 100644 --- a/app/Http/Controllers/VoucherController.php +++ b/app/Http/Controllers/VoucherController.php @@ -3,6 +3,8 @@ namespace App\Http\Controllers; use App\Models\CustomerLevel; +use App\Models\Location; +use App\Models\LocationProfile; use App\Models\Voucher; use App\Services\GeneralService; use Illuminate\Http\Request; @@ -11,22 +13,57 @@ use Illuminate\Support\Str; class VoucherController extends Controller { - public function index(Request $request) + public function location(Request $request) { - $query = Voucher::with(['location'])->orderBy('updated_at', 'desc'); + $query = Location::orderBy('updated_at', 'desc'); if ($request->q != '') { - $query->where('username', 'like', "%$request->q%") - ->orWhere('comment', 'like', "%$request->q%") - ->orWhere('profile', 'like', "%$request->q%"); + $query->where('name', 'like', "%$request->q%"); } + return inertia('Voucher/Location', [ + 'query' => tap($query->paginate(20))->append(['count_vouchers']), + ]); + } + + public function profile(Request $request, Location $location) + { + $query = LocationProfile::where('location_id', $location->id) + ->orderBy('updated_at', 'desc'); + if ($request->location_id != '') { $query->where('location_id', $request->location_id); } + if ($request->q != '') { + $query->where('name', 'like', "%$request->q%") + ->orWhere('display_note', 'like', "%$request->q%"); + } + + return inertia('Voucher/Profile', [ + 'query' => tap($query->paginate(20))->append(['count_vouchers']), + 'location' => $location, + 'stats' => Voucher::stats($location), + ]); + } + + public function index(Request $request, Location $location, LocationProfile $profile) + { + $query = Voucher::with(['profile.location']) + ->where('location_profile_id', $profile->id) + ->orderBy('updated_at', 'desc'); + + if ($request->q != '') { + $query->where('username', 'like', "%$request->q%") + ->orWhere('comment', 'like', "%$request->q%") + ->orWhere('profile', 'like', "%$request->q%"); + } + return inertia('Voucher/Index', [ 'query' => $query->paginate(), + 'location' => $location, + 'profile' => $profile, + 'stats' => Voucher::stats($location), ]); } @@ -40,55 +77,22 @@ class VoucherController extends Controller public function store(Request $request) { $request->validate([ - 'name' => 'nullable|string', - 'description' => 'nullable|string', - 'location_id' => 'required|exists:locations,id', + 'location_profile_id' => 'required|exists:location_profiles,id', 'username' => 'required|string', - 'password' => 'required|string', - 'discount' => 'required|numeric', - 'display_price' => 'required|numeric', - 'price_poin' => 'nullable|numeric', - 'quota' => 'required|string', - 'profile' => 'required|string', - 'comment' => 'required|string', - 'expired' => 'required|numeric', - 'expired_unit' => 'required|string', - 'prices' => 'nullable|array', - 'prices.*.customer_level_id' => 'required|exists:customer_levels,id', - 'prices.*.display_price' => 'required|numeric', ]); - DB::beginTransaction(); - $voucher = Voucher::create([ - 'name' => $request->name, - 'description' => $request->description, - 'location_id' => $request->location_id, + Voucher::create([ + 'location_profile_id' => $request->location_profile_id, 'username' => $request->username, - 'password' => $request->password, - 'discount' => $request->discount, - 'display_price' => $request->display_price, - 'price_poin' => $request->price_poin, - 'quota' => $request->quota, - 'profile' => $request->profile, - 'comment' => $request->comment, - 'expired' => $request->expired, - 'expired_unit' => $request->expired_unit, + 'password' => $request->username, ]); - foreach (collect($request->prices) as $price) { - $finalPrice = $price['display_price']; - if ($voucher->discount > 0) { - $finalPrice = $finalPrice - round($finalPrice * ($voucher->discount / 100), 2); - } - $voucher->prices()->create([ - 'customer_level_id' => $price['customer_level_id'], - 'price' => $finalPrice, - 'display_price' => $price['display_price'], - ]); - } - DB::commit(); + $profile = LocationProfile::find($request->location_profile_id); - return redirect()->route('voucher.index') + return redirect()->route('voucher.index', [ + 'location' => $profile->location_id, + 'profile' => $profile->id + ]) ->with('message', ['type' => 'success', 'message' => 'Item has beed saved']); } @@ -103,62 +107,22 @@ class VoucherController extends Controller public function update(Request $request, Voucher $voucher) { $request->validate([ - 'name' => 'nullable|string', - 'description' => 'nullable|string', - 'location_id' => 'required|exists:locations,id', + 'location_profile_id' => 'required|exists:location_profiles,id', 'username' => 'required|string', - 'password' => 'required|string', - 'discount' => 'required|numeric', - 'display_price' => 'required|numeric', - 'price_poin' => 'nullable|numeric', - 'quota' => 'required|string', - 'profile' => 'required|string', - 'comment' => 'required|string', - 'expired' => 'required|numeric', - 'expired_unit' => 'required|string', - 'prices' => 'nullable|array', - 'prices.*.customer_level_id' => 'required|exists:customer_levels,id', - 'prices.*.display_price' => 'required|numeric', ]); - DB::beginTransaction(); - $voucher->update([ + 'location_profile_id' => $request->location_profile_id, 'username' => $request->username, - 'password' => $request->password, + 'password' => $request->username, ]); - $vouchers = Voucher::where('batch_id', $voucher->batch_id); - $vouchers->update([ - 'name' => $request->name, - 'description' => $request->description, - 'location_id' => $request->location_id, - 'discount' => $request->discount, - 'display_price' => $request->display_price, - 'price_poin' => $request->price_poin, - 'quota' => $request->quota, - 'profile' => $request->profile, - 'comment' => $request->comment, - 'expired' => $request->expired, - ]); + $profile = LocationProfile::find($request->location_profile_id); - foreach ($vouchers->get() as $voucher) { - $voucher->prices()->delete(); - foreach (collect($request->prices) as $price) { - $finalPrice = $price['display_price']; - if ($voucher->discount > 0) { - $finalPrice = $finalPrice - round($finalPrice * ($voucher->discount / 100), 2); - } - $voucher->prices()->create([ - 'customer_level_id' => $price['customer_level_id'], - 'price' => $finalPrice, - 'display_price' => $price['display_price'], - ]); - } - } - DB::commit(); - - return redirect()->route('voucher.index') + return redirect()->route('voucher.index', [ + 'location' => $profile->location_id, + 'profile' => $profile->id + ]) ->with('message', ['type' => 'success', 'message' => 'Item has beed updated']); } @@ -166,67 +130,55 @@ class VoucherController extends Controller { $voucher->delete(); - return redirect()->route('voucher.index') + return redirect()->route('voucher.index', [ + 'location' => $voucher->profile->location_id, + 'profile' => $voucher->profile->id + ]) ->with('message', ['type' => 'success', 'message' => 'Item has beed deleted']); } public function form_import() { - return inertia('Voucher/Import', [ - 'levels' => CustomerLevel::all(), - ]); + return inertia('Voucher/Import'); } public function import(Request $request) { $request->validate([ 'script' => 'required|string', - 'location_id' => 'required|exists:locations,id', - 'discount' => 'required|numeric', - 'display_price' => 'required|numeric', - 'price_poin' => 'nullable|numeric', - 'expired' => 'required|numeric', - 'expired_unit' => 'required|string', - 'prices' => 'nullable|array', - 'prices.*.customer_level_id' => 'required|exists:customer_levels,id', - 'prices.*.display_price' => 'required|numeric', + 'location_profile_id' => 'required|exists:location_profiles,id', + ]); + $profile = LocationProfile::find($request->location_profile_id); - $batchId = Str::ulid(); $vouchers = GeneralService::script_parser($request->script); + if (count($vouchers) <= 0) { + return redirect()->route('voucher.index', [ + 'location' => $profile->location_id, + 'profile' => $profile->id + ]) + ->with('message', ['type' => 'error', 'message' => 'Nothing to import']); + } + DB::beginTransaction(); foreach ($vouchers as $voucher) { $voucher = Voucher::create([ - 'location_id' => $request->location_id, + 'location_profile_id' => $request->location_profile_id, 'username' => $voucher['username'], 'password' => $voucher['password'], - 'discount' => $request->discount, - 'display_price' => $request->display_price, - 'price_poin' => $request->price_poin, 'quota' => $voucher['quota'], 'profile' => $voucher['profile'], 'comment' => $voucher['comment'], - 'expired' => $request->expired, - 'expired_unit' => $request->expired_unit, - 'batch_id' => $batchId, ]); - - foreach (collect($request->prices) as $price) { - $finalPrice = $price['display_price']; - if ($voucher->discount > 0) { - $finalPrice = $finalPrice - round($finalPrice * ($voucher->discount / 100), 2); - } - $voucher->prices()->create([ - 'customer_level_id' => $price['customer_level_id'], - 'price' => $finalPrice, - 'display_price' => $price['display_price'], - ]); - } } DB::commit(); - return redirect()->route('voucher.index') + + return redirect()->route('voucher.index', [ + 'location' => $profile->location_id, + 'profile' => $profile->id + ]) ->with('message', ['type' => 'success', 'message' => 'Items has beed saved']); } } diff --git a/app/Models/Account.php b/app/Models/Account.php index 2143e73..c59acb9 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -9,5 +9,7 @@ class Account extends Model 'bank_name', 'holder_name', 'account_number', + 'logo', + 'admin_fee', ]; } diff --git a/app/Models/Location.php b/app/Models/Location.php index 273cdef..5f200dd 100644 --- a/app/Models/Location.php +++ b/app/Models/Location.php @@ -2,6 +2,8 @@ namespace App\Models; +use Illuminate\Database\Eloquent\Casts\Attribute; + class Location extends Model { protected $fillable = [ @@ -9,4 +11,26 @@ class Location extends Model 'description', 'logo', ]; + + public function profiles() + { + return $this->hasMany(LocationProfile::class); + } + + public function countVouchers(): Attribute + { + return Attribute::make(get: function () { + $profiles = $this->profiles()->select('id', 'min_stock')->get(); + $minStock = $profiles->min('min_stock'); + $profileIds = $profiles->pluck('id')->toArray(); + $unsoldCount = Voucher::whereIn('location_profile_id', $profileIds) + ->where('is_sold', Voucher::UNSOLD) + ->count(); + + return [ + 'color' => $unsoldCount <= $minStock ? 'bg-red-200 border-red-500' : 'bg-green-200 border-green-500', + 'unsold_count' => $unsoldCount, + ]; + }); + } } diff --git a/app/Models/LocationProfile.php b/app/Models/LocationProfile.php index 78c9075..1d2414a 100644 --- a/app/Models/LocationProfile.php +++ b/app/Models/LocationProfile.php @@ -70,10 +70,27 @@ class LocationProfile extends Model return $this->belongsTo(Location::class); } + public function vouchers() + { + return $this->hasMany(Voucher::class); + } + public function diplayExpired(): Attribute { return Attribute::make(get: function () { - return $this->expired . ' ' . $this->expired_unit; + return $this->expired.' '.$this->expired_unit; + }); + } + + public function countVouchers(): Attribute + { + return Attribute::make(get: function () { + $unsoldCount = $this->vouchers()->where('is_sold', Voucher::UNSOLD)->count(); + + return [ + 'color' => $unsoldCount <= $this->min_stock ? 'bg-red-200 border-red-500' : 'bg-green-200 border-green-500', + 'unsold_count' => $unsoldCount, + ]; }); } } diff --git a/app/Models/Sale.php b/app/Models/Sale.php index 2538ed9..90d6738 100644 --- a/app/Models/Sale.php +++ b/app/Models/Sale.php @@ -15,7 +15,7 @@ class Sale extends Model const PAYED_WITH_PAYLATER = 'paylater'; - const PAYED_WITH_poin = 'poin'; + const PAYED_WITH_POIN = 'poin'; protected $fillable = [ 'code', @@ -69,7 +69,7 @@ class Sale extends Model public function create_notification() { - if ($this->payed_with == self::PAYED_WITH_poin) { + if ($this->payed_with == self::PAYED_WITH_POIN) { Notification::create([ 'entity_type' => User::class, 'description' => $this->customer->fullname.' melakukan penukaran '.$this->items()->count().' voucher sebesar '.$this->items->value('price').' poin', diff --git a/app/Models/Voucher.php b/app/Models/Voucher.php index d65775f..53c7081 100644 --- a/app/Models/Voucher.php +++ b/app/Models/Voucher.php @@ -2,6 +2,8 @@ namespace App\Models; +use Illuminate\Database\Eloquent\Casts\Attribute; + class Voucher extends Model { const UNSOLD = 0; @@ -20,7 +22,48 @@ class Voucher extends Model 'is_sold', //menandakan sudah terjual atau belum ]; - protected $appends = ['display_quota', 'display_expired', 'validate_price', 'validate_display_price']; + protected $appends = [ + 'validate_price', + 'validate_display_price', + 'status', + 'created_at_formated' + ]; + + public function profile() + { + return $this->belongsTo(LocationProfile::class, 'location_profile_id'); + } + + public function validatePrice(): Attribute + { + return Attribute::make(get: function () { + return ''; + }); + } + + public function validateDisplayPrice(): Attribute + { + return Attribute::make(get: function () { + return ''; + }); + } + + public function status(): Attribute + { + return Attribute::make(get: function () { + return [ + 'color' => $this->sold == self::SOLD ? 'bg-green-200 border-green-600' : 'bg-yellow-100 border-yellow-300', + 'text' => $this->sold == self::SOLD ? 'Ya' : 'Tidak' + ]; + }); + } + + public function createdAtFormated(): Attribute + { + return Attribute::make(get: function () { + return $this->created_at->format('d/m/Y H:i:s'); + }); + } public function shuffle_unsold() { @@ -54,8 +97,45 @@ class Voucher extends Model if ($count <= $treshold) { Notification::create([ 'entity_type' => User::class, - 'description' => 'stok voucher '.$this->location->name.' ( '.$this->profile.' ) '.'tersisa : '.$count, + 'description' => 'stok voucher ' . $this->location->name . ' ( ' . $this->profile . ' ) ' . 'tersisa : ' . $count, ]); } } + + public static function stats(Location $location) + { + + $profileIds = LocationProfile::where('location_id', $location->id)->pluck('id')->toArray(); + + $count_voucher_total = Voucher::whereIn('location_profile_id', $profileIds)->count(); + $sum_voucher_total = Voucher::whereIn('location_profile_id', $profileIds) + ->join('location_profiles', 'location_profiles.id', '=', 'vouchers.location_profile_id') + ->selectRaw('(count(vouchers.id) * location_profiles.price) as total') + ->value('total'); + $count_voucher_sold = Voucher::whereIn('location_profile_id', $profileIds)->where('is_sold', Voucher::SOLD)->count(); + $count_voucher_unsold = Voucher::whereIn('location_profile_id', $profileIds)->where('is_sold', Voucher::UNSOLD)->count(); + $sum_voucher_unsold = Voucher::whereIn('location_profile_id', $profileIds) + ->where('is_sold', Voucher::UNSOLD) + ->join('location_profiles', 'location_profiles.id', '=', 'vouchers.location_profile_id') + ->selectRaw('(count(vouchers.id) * location_profiles.price) as total') + ->value('total'); + + $voucherIds = Voucher::whereIn('location_profile_id', $profileIds)->pluck('id')->toArray(); + $sum_voucher_sold = SaleItem::whereIn('entity_id', $voucherIds) + ->whereHas('sale', function ($q) { + $q->where('payed_with', Sale::PAYED_WITH_DEPOSIT) + ->orWhere('payed_with', Sale::PAYED_WITH_PAYLATER); + }) + ->selectRaw('SUM(price * quantity) as total') + ->value('total'); + + return [ + 'count_voucher_total' => $count_voucher_total, + 'sum_voucher_total' => $sum_voucher_total, + 'count_voucher_sold' => $count_voucher_sold, + 'sum_voucher_sold' => $sum_voucher_sold, + 'count_voucher_unsold' => $count_voucher_unsold, + 'sum_voucher_unsold' => $sum_voucher_unsold, + ]; + } } diff --git a/composer.json b/composer.json index 5d3c325..eb22356 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "require-dev": { "beyondcode/laravel-dump-server": "^1.9", "fakerphp/faker": "^1.23.0", - "laradumps/laradumps": "^1.12.3", + "laradumps/laradumps": "^1.12", "laravel/breeze": "^1.21.0", "laravel/pint": "^1.10.2", "laravel/sail": "^1.22.0", diff --git a/composer.lock b/composer.lock index 257dfae..4e2891b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "37cb54e2418cfe92a600a5757cb08191", + "content-hash": "1dc99b21d1aa2534f1a2a2e6f28ed566", "packages": [ { "name": "brick/math", diff --git a/database/seeders/DummySeeder.php b/database/seeders/DummySeeder.php index c80fe26..cd081b7 100644 --- a/database/seeders/DummySeeder.php +++ b/database/seeders/DummySeeder.php @@ -12,6 +12,7 @@ use App\Models\Voucher; use App\Services\GeneralService; use Illuminate\Database\Seeder; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Str; class DummySeeder extends Seeder { @@ -43,8 +44,8 @@ class DummySeeder extends Seeder $images = ['1.webp', '2.webp', '3.webp']; foreach ($images as $index => $image) { Banner::create([ - 'title' => 'Banner ' . $index, - 'image' => 'sample/' . $image, + 'title' => 'Banner '.$index, + 'image' => 'sample/'.$image, 'description' => '

Banner

', ]); } @@ -69,11 +70,13 @@ class DummySeeder extends Seeder public function location() { - $locations = ['Jarbriel.id', 'Shaff.net', 'Weslycamp.net', 'Glory.net', 'Salgo.id', 'Terna.id', 'Kanza.id']; + $locations = [ + 'jabriel.id', 'shaff.net', 'weslycamp.net', 'glory.net', 'agelos.net', 'brigton.ne', 'tairon.net', 'jeconia.net', 'metsawifi.net', 'donata.net', 'hoptar.id', 'salgo.id', 'feivel.id', 'carenet.id', 'ivena.id', 'dishan.id', 'imago.id', 'netif.id', 'gavi.id', 'terna.id', 'kanza.id', 'benaya.id', 'rega.id', 'ponix.id', 'drago.id', 'lexsa.id', 'kilia.id', 'gramanta.id', 'vermil.id', 'nohea.id', 'ducan.id', 'letra.id', 'lejau.id', 'jelivan', 'takahiro.id', 'katsu', 'zergan', 'satoshi', + ]; foreach ($locations as $location) { Location::create([ - 'name' => $location, + 'name' => Str::ucfirst($location), 'description' => '-', ]); } @@ -99,7 +102,7 @@ class DummySeeder extends Seeder $lp = LocationProfile::create([ 'location_id' => $location->id, - 'name' => $quota, + 'name' => 'Profile '.$quota, 'quota' => $quota, 'display_note' => 'bisa semua', 'expired' => rand(1, 3), @@ -145,8 +148,7 @@ class DummySeeder extends Seeder $vouchers = GeneralService::script_parser(file_get_contents(public_path('example.md'))); DB::beginTransaction(); - foreach ([1, 2, 3] as $loop) { - $profile = LocationProfile::get()[$loop]; + foreach (LocationProfile::limit(9)->get() as $profile) { foreach ($vouchers as $voucher) { Voucher::create([ 'location_profile_id' => $profile->id, diff --git a/resources/js/Components/Pagination.jsx b/resources/js/Components/Pagination.jsx index e0f06a5..e47add0 100644 --- a/resources/js/Components/Pagination.jsx +++ b/resources/js/Components/Pagination.jsx @@ -3,7 +3,9 @@ import { HiOutlineChevronLeft, HiOutlineChevronRight } from 'react-icons/hi' import qs from 'qs' const PageLink = ({ active, label, url, params }) => { - const className = active ? 'z-10 px-3 py-2 leading-tight text-blue-600 border border-blue-300 bg-blue-50 hover:bg-blue-100 hover:text-blue-700 dark:border-gray-700 dark:bg-gray-700 dark:text-white' : 'px-3 py-2 leading-tight text-gray-500 bg-white border border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white' + const className = active + ? 'z-10 px-3 py-2 leading-tight text-blue-600 border border-blue-300 bg-blue-50 hover:bg-blue-100 hover:text-blue-700 dark:border-gray-700 dark:bg-gray-700 dark:text-white' + : 'px-3 py-2 leading-tight text-gray-500 bg-white border border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white' const onClick = () => { router.get( @@ -24,7 +26,7 @@ const PageLink = ({ active, label, url, params }) => { className="block py-2 px-1 ml-0 leading-tight text-gray-500 bg-white border border-gray-300 rounded-l-lg hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white" aria-label="Previous" > - + ) @@ -34,8 +36,9 @@ const PageLink = ({ active, label, url, params }) => {
  • ) @@ -44,7 +47,7 @@ const PageLink = ({ active, label, url, params }) => { return (
  • ) @@ -62,7 +65,7 @@ const PageInactive = ({ label }) => { disabled={true} aria-label="Previous" > - + ) @@ -71,11 +74,11 @@ const PageInactive = ({ label }) => { return (
  • ) @@ -111,4 +114,4 @@ export default ({ links = [], params = null }) => { ) -} \ No newline at end of file +} diff --git a/resources/js/Components/SearchInput.jsx b/resources/js/Components/SearchInput.jsx index fc07827..d73111f 100644 --- a/resources/js/Components/SearchInput.jsx +++ b/resources/js/Components/SearchInput.jsx @@ -1,20 +1,20 @@ -import React from "react"; -import { HiSearch } from "react-icons/hi"; +import React from 'react' +import { HiSearch } from 'react-icons/hi' export default function SearchInput({ onChange, value }) { return (
    - +
    -
    ) -} \ No newline at end of file +} diff --git a/resources/js/Layouts/AuthenticatedLayout.jsx b/resources/js/Layouts/AuthenticatedLayout.jsx index 989e19c..5325a39 100644 --- a/resources/js/Layouts/AuthenticatedLayout.jsx +++ b/resources/js/Layouts/AuthenticatedLayout.jsx @@ -10,14 +10,13 @@ import SidebarNav from './Partials/SidebarNav' import { HiOutlineBell } from 'react-icons/hi2' export default function Authenticated({ - auth, children, - flash, page = '', action = '', + parent = null, }) { const { - props: { count_unread_notifications, notifications }, + props: { count_unread_notifications, notifications, auth, flash }, } = usePage() const [showingNavigationDropdown, setShowingNavigationDropdown] = useState(false) @@ -162,16 +161,26 @@ export default function Authenticated({
    {page !== '' && ( - - router.visit(route('dashboard'))} - icon={HiHome} - > + + parent === null + ? router.visit(route('dashboard')) + : router.visit(parent) + } + > +

    {page}

    - {action !== '' && ( + {typeof action === 'string' && ( {action} )} + {typeof action === 'object' && + action.map((item) => ( + + {item} + + ))}
    )}
    {children}
    diff --git a/resources/js/Layouts/Partials/SidebarNav.jsx b/resources/js/Layouts/Partials/SidebarNav.jsx index df2571b..f4d1937 100644 --- a/resources/js/Layouts/Partials/SidebarNav.jsx +++ b/resources/js/Layouts/Partials/SidebarNav.jsx @@ -1,21 +1,55 @@ import React from 'react' -import { router, usePage } from '@inertiajs/react' +import { Link, router } 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 { - props: { app_name }, - } = usePage() +const Item = ({ item, children }) => { + const Icon = () => + item.icon({ + className: + 'w-6 h-6 text-gray-500 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white', + }) + const isActive = route().current(item.active) + const className = `flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 ${ + isActive && 'bg-gray-200' + }` + return ( + + + {children} + + ) +} + +const SubItem = ({ item, children }) => { + const Icon = () => + item.icon({ + className: + 'w-6 h-6 text-gray-500 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white', + }) + const isActive = route().current(item.active) + const className = `flex items-center w-full p-2 text-gray-900 transition duration-75 rounded-lg pl-11 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700 ${ + isActive && 'bg-gray-200' + }` + + return ( + + + {children} + + ) +} + +export default function SidebarNav({ user }) { 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)) { @@ -32,13 +66,7 @@ export default function SidebarNav({ user }) { {menus.map((item) => (
    {item.items === undefined ? ( - router.visit(item.route)} - icon={item.icon} - active={route().current(item.active)} - > - {item.name} - + {item.name} ) : ( {item.items.map((item) => ( - - router.visit(item.route) - } - icon={item.icon} - active={route().current( - item.active - )} - > + {item.name} - + ))} )} @@ -71,7 +90,7 @@ export default function SidebarNav({ user }) {

    - {app_name} © {new Date().getFullYear()} + Elsoft © {new Date().getFullYear()}

    diff --git a/resources/js/Layouts/Partials/helpers.js b/resources/js/Layouts/Partials/helpers.js index 4450946..7a6fa74 100644 --- a/resources/js/Layouts/Partials/helpers.js +++ b/resources/js/Layouts/Partials/helpers.js @@ -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 } -} \ No newline at end of file +} diff --git a/resources/js/Layouts/Partials/routes.js b/resources/js/Layouts/Partials/routes.js index fbeb14e..63cd64f 100644 --- a/resources/js/Layouts/Partials/routes.js +++ b/resources/js/Layouts/Partials/routes.js @@ -16,6 +16,7 @@ import { HiOutlineCurrencyDollar, HiOutlineGlobeAlt, HiQuestionMarkCircle, + HiShoppingCart, HiTicket, HiUserCircle, } from 'react-icons/hi2' @@ -49,14 +50,14 @@ export default [ name: 'Voucher', show: true, icon: HiTicket, - route: route('voucher.index'), + route: route('voucher.location'), active: 'voucher.*', permission: 'view-voucher', }, { name: 'Sale', show: true, - icon: HiCreditCard, + icon: HiShoppingCart, route: route('sale.index'), active: 'sale.*', permission: 'view-sale', @@ -133,12 +134,12 @@ export default [ ], }, { - name: 'User', + name: 'Admin', show: true, icon: HiUser, items: [ { - name: 'Roles', + name: 'Rule Admin', show: true, icon: HiUserGroup, route: route('roles.index'), @@ -146,7 +147,7 @@ export default [ permission: 'view-role', }, { - name: 'Users', + name: 'List Admin', show: true, icon: HiUsers, route: route('user.index'), diff --git a/resources/js/Pages/Account/Index.jsx b/resources/js/Pages/Account/Index.jsx index a1ed482..c5c0e40 100644 --- a/resources/js/Pages/Account/Index.jsx +++ b/resources/js/Pages/Account/Index.jsx @@ -42,13 +42,7 @@ export default function Account(props) { const canDelete = hasPermission(auth, 'delete-account') return ( - +
    diff --git a/resources/js/Pages/Banner/Form.jsx b/resources/js/Pages/Banner/Form.jsx index e9c9ed9..fec694c 100644 --- a/resources/js/Pages/Banner/Form.jsx +++ b/resources/js/Pages/Banner/Form.jsx @@ -48,13 +48,7 @@ export default function Form(props) { }, [banner]) return ( - +
    diff --git a/resources/js/Pages/Banner/Index.jsx b/resources/js/Pages/Banner/Index.jsx index 03f690b..77ed89f 100644 --- a/resources/js/Pages/Banner/Index.jsx +++ b/resources/js/Pages/Banner/Index.jsx @@ -35,13 +35,7 @@ export default function Info(props) { const canDelete = hasPermission(auth, 'delete-banner') return ( - +
    diff --git a/resources/js/Pages/Customer/Form.jsx b/resources/js/Pages/Customer/Form.jsx index c235f58..cd21c70 100644 --- a/resources/js/Pages/Customer/Form.jsx +++ b/resources/js/Pages/Customer/Form.jsx @@ -220,13 +220,7 @@ const Paylater = () => { export default function Form(props) { return ( - +
    diff --git a/resources/js/Pages/Customer/Index.jsx b/resources/js/Pages/Customer/Index.jsx index 7639fa1..a2ad2e1 100644 --- a/resources/js/Pages/Customer/Index.jsx +++ b/resources/js/Pages/Customer/Index.jsx @@ -53,13 +53,7 @@ export default function Customer(props) { const canDelete = hasPermission(auth, 'delete-customer') return ( - +
    diff --git a/resources/js/Pages/CustomerLevel/Index.jsx b/resources/js/Pages/CustomerLevel/Index.jsx index c471521..cf73821 100644 --- a/resources/js/Pages/CustomerLevel/Index.jsx +++ b/resources/js/Pages/CustomerLevel/Index.jsx @@ -25,13 +25,7 @@ export default function Info(props) { const canUpdate = hasPermission(auth, 'update-customer-level') return ( - +
    diff --git a/resources/js/Pages/Dashboard.jsx b/resources/js/Pages/Dashboard.jsx index f94082b..b60f02e 100644 --- a/resources/js/Pages/Dashboard.jsx +++ b/resources/js/Pages/Dashboard.jsx @@ -94,13 +94,7 @@ export default function Dashboard(props) { }, [dates, customer_id, location_id]) return ( - +
    diff --git a/resources/js/Pages/DepositHistory/Index.jsx b/resources/js/Pages/DepositHistory/Index.jsx index e93d1a9..cf154e4 100644 --- a/resources/js/Pages/DepositHistory/Index.jsx +++ b/resources/js/Pages/DepositHistory/Index.jsx @@ -44,13 +44,7 @@ export default function Index(props) { const canUpdate = hasPermission(auth, 'update-deposit') return ( - +
    diff --git a/resources/js/Pages/Info/Index.jsx b/resources/js/Pages/Info/Index.jsx index c9c6c60..ff8b30c 100644 --- a/resources/js/Pages/Info/Index.jsx +++ b/resources/js/Pages/Info/Index.jsx @@ -43,13 +43,7 @@ export default function Info(props) { const canDelete = hasPermission(auth, 'delete-info') return ( - +
    diff --git a/resources/js/Pages/Location/Index.jsx b/resources/js/Pages/Location/Index.jsx index 40ad58e..7212289 100644 --- a/resources/js/Pages/Location/Index.jsx +++ b/resources/js/Pages/Location/Index.jsx @@ -19,6 +19,9 @@ export default function Index(props) { auth, } = props + const [search, setSearch] = useState('') + const preValue = usePrevious(`${search}`) + const confirmModal = useModalState() const formModal = useModalState() @@ -38,24 +41,32 @@ export default function Index(props) { } } + const params = { q: search } + useEffect(() => { + if (preValue) { + router.get( + route(route().current()), + { q: search }, + { + replace: true, + preserveState: true, + } + ) + } + }, [search]) + const canCreate = hasPermission(auth, 'create-location') const canUpdate = hasPermission(auth, 'update-location') const canDelete = hasPermission(auth, 'delete-location') return ( - +
    -
    +
    {canCreate && (
    @@ -151,7 +172,7 @@ export default function Index(props) {
    - +
    diff --git a/resources/js/Pages/LocationProfile/Form.jsx b/resources/js/Pages/LocationProfile/Form.jsx index fddf8de..66674fb 100644 --- a/resources/js/Pages/LocationProfile/Form.jsx +++ b/resources/js/Pages/LocationProfile/Form.jsx @@ -114,13 +114,7 @@ export default function Form(props) { }, [profile]) return ( - +
    diff --git a/resources/js/Pages/LocationProfile/Index.jsx b/resources/js/Pages/LocationProfile/Index.jsx index c461ef9..4f0fc89 100644 --- a/resources/js/Pages/LocationProfile/Index.jsx +++ b/resources/js/Pages/LocationProfile/Index.jsx @@ -6,12 +6,12 @@ import { Button, Dropdown } from 'flowbite-react' import { HiPencil, HiTrash } from 'react-icons/hi' import { useModalState } from '@/hooks' +import { hasPermission } from '@/utils' import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout' import Pagination from '@/Components/Pagination' import ModalConfirm from '@/Components/ModalConfirm' import SearchInput from '@/Components/SearchInput' import LocationSelectionInput from '../Location/SelectionInput' -import { hasPermission } from '@/utils' export default function Index(props) { const { @@ -57,19 +57,13 @@ export default function Index(props) { const canDelete = hasPermission(auth, 'delete-location-profile') return ( - +
    -
    +
    {canCreate && (
    - {/* - - */}
    )} -
    - setLocation(id)} - placeholder={'filter lokasi'} - /> - setSearch(e.target.value)} - value={search} - /> +
    +
    + setLocation(id)} + placeholder={'filter lokasi'} + /> +
    +
    + + setSearch(e.target.value) + } + value={search} + /> +
    @@ -210,7 +203,7 @@ export default function Index(props) {
    -
    +
    diff --git a/resources/js/Pages/LocationProfile/SelectionInput.jsx b/resources/js/Pages/LocationProfile/SelectionInput.jsx new file mode 100644 index 0000000..87516c0 --- /dev/null +++ b/resources/js/Pages/LocationProfile/SelectionInput.jsx @@ -0,0 +1,269 @@ +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.location.name} - ${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.location-profile.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.location.name} - ${item.name}`) + setIsSelected(true) + } + return + } + setIsSelected(false) + }, [itemSelected, loading]) + + useEffect(() => { + if (isSelected && selected === '') { + setSelected('') + setIsSelected(false) + } + }, [isSelected]) + + return ( +
    +
    +
    +
    + {label !== '' && ( + + )} +
    +
    + + filterItems(e.target.value) + } + disabled={disabled} + /> + {isSelected && ( +
    {} : removeItem + } + > + +
    + )} +
    {} : toggle}> + +
    +
    + {error && ( +

    + {error} +

    + )} +
    + {isOpen && ( +
    +
    + {loading ? ( +
    +
    +
    +
    + + Loading... +
    +
    +
    +
    + ) : ( + <> + {showItems.map((item, index) => ( +
    + handleSelectItem(item) + } + > +
    +
    +
    + + { + item + .location + .name + }{' '} + -{' '} + {item.name} + +
    +
    +
    +
    + ))} + {showItems.length <= 0 && ( +
    +
    +
    +
    + + No Items + Found + +
    +
    +
    +
    + )} + + )} +
    +
    + )} +
    +
    +
    +
    + ) +} diff --git a/resources/js/Pages/Maintance.jsx b/resources/js/Pages/Maintance.jsx index 56a5c91..ecaa42a 100644 --- a/resources/js/Pages/Maintance.jsx +++ b/resources/js/Pages/Maintance.jsx @@ -1,27 +1,23 @@ -import React from 'react'; -import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout'; -import { Head } from '@inertiajs/react'; -import { HiFire } from 'react-icons/hi'; +import React from 'react' +import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout' +import { Head } from '@inertiajs/react' +import { HiFire } from 'react-icons/hi' export default function Maintance(props) { return ( - +
    - -
    Fitur Dalam Pengembangan
    + +
    + Fitur Dalam Pengembangan +
    - ); -} \ No newline at end of file + ) +} diff --git a/resources/js/Pages/Notification/Index.jsx b/resources/js/Pages/Notification/Index.jsx index 084745c..980b0f5 100644 --- a/resources/js/Pages/Notification/Index.jsx +++ b/resources/js/Pages/Notification/Index.jsx @@ -18,13 +18,7 @@ export default function Index(props) { router.get(route(route().current())) } return ( - +
    diff --git a/resources/js/Pages/PoinReward/Index.jsx b/resources/js/Pages/PoinReward/Index.jsx index 1697d52..9bec901 100644 --- a/resources/js/Pages/PoinReward/Index.jsx +++ b/resources/js/Pages/PoinReward/Index.jsx @@ -41,13 +41,7 @@ export default function Info(props) { const canDelete = hasPermission(auth, 'delete-poin-reward') return ( - +
    diff --git a/resources/js/Pages/Role/Form.jsx b/resources/js/Pages/Role/Form.jsx index f3db287..38bcf0c 100644 --- a/resources/js/Pages/Role/Form.jsx +++ b/resources/js/Pages/Role/Form.jsx @@ -1,92 +1,107 @@ -import React, { useEffect, useState } from 'react'; -import { Head, Link, useForm, usePage } from '@inertiajs/react'; +import React, { useEffect, useState } from 'react' +import { Head, Link, useForm, usePage } from '@inertiajs/react' -import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout'; -import FormInput from '@/Components/FormInput'; -import Button from '@/Components/Button'; -import { isEmpty } from 'lodash'; -import Checkbox from '@/Components/Checkbox'; -import { router } from '@inertiajs/react'; +import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout' +import FormInput from '@/Components/FormInput' +import Button from '@/Components/Button' +import { isEmpty } from 'lodash' +import Checkbox from '@/Components/Checkbox' +import { router } from '@inertiajs/react' export default function Role(props) { - const { props: { errors } } = usePage() + const { + props: { errors }, + } = usePage() const { permissions, role } = props const [processing, setProcessing] = useState(false) - const [name, setName] = useState('') - const [permins, setPermins] = useState(permissions.map(permin => { return {...permin, checked: false} })) + const [permins, setPermins] = useState( + permissions.map((permin) => { + return { ...permin, checked: false } + }) + ) const handleCheckPermission = (e) => { - setPermins(permins.map(item => { - if(item.name === e.target.name) { - return { - ...item, - checked: !item.checked + setPermins( + permins.map((item) => { + if (item.name === e.target.name) { + return { + ...item, + checked: !item.checked, + } } - } - return item - })) + return item + }) + ) } const handleCheckAll = (e) => { - setPermins(permins.map(item => { - return { - ...item, - checked: e.target.checked, - } - })) + setPermins( + permins.map((item) => { + return { + ...item, + checked: e.target.checked, + } + }) + ) } const handleSubmit = () => { - if(isEmpty(role) === false) { - router.put(route('roles.update', role), { + if (isEmpty(role) === false) { + router.put( + route('roles.update', role), + { + name: name, + permissions: permins.filter((item) => item.checked), + }, + { + onStart: () => setProcessing(true), + onFinish: (e) => { + setProcessing(false) + }, + } + ) + return + } + router.post( + route('roles.store'), + { name: name, - permissions: permins.filter(item => item.checked) - }, { + permissions: permins.filter((item) => item.checked), + }, + { onStart: () => setProcessing(true), onFinish: (e) => { setProcessing(false) - } - }) - return - } - router.post(route('roles.store'), { - name: name, - permissions: permins.filter(item => item.checked) - }, { - onStart: () => setProcessing(true), - onFinish: (e) => { - setProcessing(false) + }, } - }) + ) } useEffect(() => { - if(!isEmpty(role)) { + if (!isEmpty(role)) { setName(role.name) - setPermins(permins.map(item => { - const isExists = role.permissions.find(permit => permit.id === item.id) - if (isExists) { - return { - ...item, - checked: true, + setPermins( + permins.map((item) => { + const isExists = role.permissions.find( + (permit) => permit.id === item.id + ) + if (isExists) { + return { + ...item, + checked: true, + } } - } - return item - })) + return item + }) + ) } }, [role]) return ( - +
    @@ -95,18 +110,22 @@ export default function Role(props) { setName(e.target.value)} + onChange={(e) => setName(e.target.value)} label="Nama" error={errors.name} /> -
    - {permins.map(item => ( + {permins.map((item) => ( {errors.permissions && ( -

    {errors.permissions}

    +

    + {errors.permissions} +

    )}
    - - - -
    + + + +
    - ); + ) } diff --git a/resources/js/Pages/Role/Index.jsx b/resources/js/Pages/Role/Index.jsx index ef5b0ee..67548a8 100644 --- a/resources/js/Pages/Role/Index.jsx +++ b/resources/js/Pages/Role/Index.jsx @@ -1,20 +1,23 @@ -import React, { useEffect, useState } from 'react'; -import { router } from '@inertiajs/react'; -import { usePrevious } from 'react-use'; -import { Head, Link } from '@inertiajs/react'; -import { Button, Dropdown } from 'flowbite-react'; -import { HiPencil, HiTrash } from 'react-icons/hi'; -import { useModalState } from '@/hooks'; +import React, { useEffect, useState } from 'react' +import { router } from '@inertiajs/react' +import { usePrevious } from 'react-use' +import { Head, Link } 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 SearchInput from '@/Components/SearchInput'; -import { hasPermission } from '@/utils'; +import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout' +import Pagination from '@/Components/Pagination' +import ModalConfirm from '@/Components/ModalConfirm' +import SearchInput from '@/Components/SearchInput' +import { hasPermission } from '@/utils' export default function Product(props) { - const { data: { links, data }, auth } = props - + const { + data: { links, data }, + auth, + } = props + const [search, setSearch] = useState('') const preValue = usePrevious(search) @@ -26,7 +29,7 @@ export default function Product(props) { } const onDelete = () => { - if(confirmModal.data !== null) { + if (confirmModal.data !== null) { router.delete(route('roles.destroy', confirmModal.data.id)) } } @@ -50,52 +53,58 @@ export default function Product(props) { const canDelete = hasPermission(auth, 'delete-role') return ( - - + +
    -
    +
    {canCreate && ( )} - +
    setSearch(e.target.value)} + onChange={(e) => setSearch(e.target.value)} value={search} />
    -
    +
    - - - {data.map(role => ( - - +
    + Nama +
    + {data.map((role) => ( +
    {role.name} {canUpdate && ( router.visit(route('roles.edit', role))} + onClick={() => + router.visit( + route( + 'roles.edit', + role + ) + ) + } > -
    - -
    Ubah
    +
    + +
    + Ubah +
    )} {canDelete && ( - handleDeleteClick(role)}> -
    - -
    Hapus
    + + handleDeleteClick( + role + ) + } + > +
    + +
    + Hapus +
    )} @@ -126,17 +152,14 @@ export default function Product(props) {
    -
    - +
    +
    - + - ); + ) } diff --git a/resources/js/Pages/Sale/Detail.jsx b/resources/js/Pages/Sale/Detail.jsx index 328a2ee..39f7889 100644 --- a/resources/js/Pages/Sale/Detail.jsx +++ b/resources/js/Pages/Sale/Detail.jsx @@ -12,13 +12,7 @@ export default function Detail(props) { const { sale } = props return ( - +
    diff --git a/resources/js/Pages/Sale/Index.jsx b/resources/js/Pages/Sale/Index.jsx index b2ab0eb..01076f9 100644 --- a/resources/js/Pages/Sale/Index.jsx +++ b/resources/js/Pages/Sale/Index.jsx @@ -31,13 +31,7 @@ export default function Info(props) { }, [search]) return ( - +
    diff --git a/resources/js/Pages/Setting/Index.jsx b/resources/js/Pages/Setting/Index.jsx index 2b8be15..1668353 100644 --- a/resources/js/Pages/Setting/Index.jsx +++ b/resources/js/Pages/Setting/Index.jsx @@ -44,9 +44,6 @@ export default function General(props) { return ( - + +
    diff --git a/resources/js/Pages/Verification/Form.jsx b/resources/js/Pages/Verification/Form.jsx index ce6a612..faa8725 100644 --- a/resources/js/Pages/Verification/Form.jsx +++ b/resources/js/Pages/Verification/Form.jsx @@ -30,13 +30,7 @@ export default function Form(props) { } return ( - +
    diff --git a/resources/js/Pages/Verification/Index.jsx b/resources/js/Pages/Verification/Index.jsx index a9d2c29..70e2b60 100644 --- a/resources/js/Pages/Verification/Index.jsx +++ b/resources/js/Pages/Verification/Index.jsx @@ -31,13 +31,7 @@ export default function Index(props) { }, [search]) return ( - +
    diff --git a/resources/js/Pages/Voucher/Form.jsx b/resources/js/Pages/Voucher/Form.jsx index a00a677..aed4cd1 100644 --- a/resources/js/Pages/Voucher/Form.jsx +++ b/resources/js/Pages/Voucher/Form.jsx @@ -109,13 +109,7 @@ export default function Form(props) { }, [voucher]) return ( - +
    diff --git a/resources/js/Pages/Voucher/Import.jsx b/resources/js/Pages/Voucher/Import.jsx index 894f308..d877168 100644 --- a/resources/js/Pages/Voucher/Import.jsx +++ b/resources/js/Pages/Voucher/Import.jsx @@ -6,55 +6,16 @@ import FormInput from '@/Components/FormInput' import Button from '@/Components/Button' import { Head, useForm } from '@inertiajs/react' import FormInputWith from '@/Components/FormInputWith' -import LocationSelectionInput from '../Location/SelectionInput' +import LocationProfileSelectionInput from '../LocationProfile/SelectionInput' import TextArea from '@/Components/TextArea' import Checkbox from '@/Components/Checkbox' export default function Import(props) { - const { levels } = props - const [use_level, setUseLevel] = useState(false) const { data, setData, post, processing, errors } = useForm({ script: '', - discount: 0, - display_price: 0, - price_poin: 0, - expired: '', - expired_unit: 'Hari', - location_id: null, - prices: null, + location_profile_id: null, }) - const handleUseLevel = () => { - setUseLevel(!use_level) - if (!use_level === true) { - const prices = levels.map((level) => { - return { - name: level.name, - customer_level_id: level.id, - display_price: '0', - } - }) - setData('prices', prices) - return - } - setData('prices', null) - } - - const handleSetLevelPrice = (id, value) => { - setData( - 'prices', - data.prices.map((price) => { - if (price.customer_level_id === id) { - return { - ...price, - display_price: value, - } - } - return price - }) - ) - } - const handleOnChange = (event) => { setData( event.target.name, @@ -65,119 +26,29 @@ export default function Import(props) { : event.target.value ) } + const handleSubmit = () => { post(route('voucher.import')) } return ( - +
    Voucher
    - setData('location_id', id)} - error={errors.location_id} + + setData('location_profile_id', id) + } + error={errors.location_profile_id} />
    - - %
    } - name="discount" - value={data.discount} - onChange={handleOnChange} - error={errors.discount} - formClassName={'pr-10'} - label="Discount" - max={100} - min={0} - /> - -
    - -
    - -
    - -
    -
    -
    - handleUseLevel(e.target.value)} - /> -
    - {data.prices?.map((price) => ( - - handleSetLevelPrice( - price.customer_level_id, - e.target.value - ) - } - label={price.name} - /> - ))} - {errors.prices && ( -

    - {errors.prices} -

    - )} -
    +