feat: Enhance product creation UI with radio buttons and switch, correct product VPS OS foreign key, remove transaction UUID migration, and refactor customer add/edit views.

This commit is contained in:
pbao9
2026-02-25 13:45:02 +07:00
parent 2ff2095062
commit 5c97768707
5 changed files with 296 additions and 239 deletions
@@ -17,7 +17,7 @@ return new class extends Migration
$table->integer('product_type')->nullable();
$table->unsignedBigInteger('os_id')->index();
$table->foreign('product_id')->references('id')->on('vps')->onDelete('cascade');
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
$table->foreign('os_id')->references('id')->on('os')->onDelete('cascade');
$table->timestamps();
});
@@ -1,22 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
public function up()
{
Schema::table('transactions', function (Blueprint $table) {
$table->uuid('uuid')->unique()->nullable()->after('id');
$table->string('public_code')->unique()->nullable()->after('uuid');
});
}
public function down()
{
Schema::table('transactions', function (Blueprint $table) {
$table->dropColumn(['uuid', 'public_code']);
});
}
};
@@ -1,115 +1,152 @@
@extends("administrator.layout.master")
@section("content")
@extends('administrator.layout.master')
@push('plugin-styles')
@foreach (config('assets.datatable.css') as $datatable)
<link href="{{ asset($datatable) }}" rel="stylesheet" />
@endforeach
@endpush
@section('breadcrumb')
@php
$breadcrumbItems = [
['label' => 'Customer'],
['label' => 'Customer Management', 'url' => route('customer.index')],
['label' => 'Add Customer', 'active' => true],
];
@endphp
<x-admin-breadcrumb :items="$breadcrumbItems" />
@endsection
@section('content')
@if(auth()->guard('admins')->user()->can("add customer"))
<div class="card card-outline card-primary">
<form action="{{ route('customer.store') }}" method="post">
@csrf
<div class="card-body">
<div class="row">
<div class="col">
{{--Fullname--}}
<div class="form-group row">
<label class="col-md-4" for="fullname">Fullname</label>
<div class="col-md-8">
<input type="text" id="fullname" name="fullname" placeholder="Fullname"
value="{{ old('fullname') }}" class="form-control">
</div>
</div>
{{--Company--}}
<div class="form-group row">
<label class="col-md-4" for="company">Company</label>
<div class="col-md-8">
<input type="text" id="company" name="company" placeholder="Company"
value="{{ old('company') }}" class="form-control">
</div>
</div>
{{--Email--}}
<div class="form-group row">
<label class="col-md-4" for="email">Email Address</label>
<div class="col-md-8">
<input type="email" id="email" name="email" placeholder="Email Address"
value="{{ old('email') }}" class="form-control">
</div>
</div>
{{--Phone--}}
<div class="form-group row">
<label class="col-md-4" for="phone">Phone Number</label>
<div class="col-md-8">
<input type="text" id="phone" name="phone" placeholder="(+84) 123. 456. 789)"
value="{{ old('phone') }}" class="form-control">
</div>
</div>
{{--Password--}}
<div class="form-group row">
<label class="col-md-4" for="password">Password</label>
<div class="col-md-8">
<input type="password" id="password" name="password" placeholder="******"
value="{{ old('password') }}" class="form-control">
</div>
</div>
<form action="{{ route('customer.store') }}" method="post">
@csrf
<div class="row align-items-start">
<div class="col-md-8">
<div class="card card-primary card-outline rounded-4 shadow-none">
<div class="card-header rounded-top-4">
<h5 class="card-title m-0">Basic Information</h5>
</div>
<div class="col">
{{--Address--}}
<div class="form-group row">
<label class="col-md-4" for="address">Address</label>
<div class="col-md-8">
<input type="text" id="address" name="address" placeholder="Address"
value="{{ old('address') }}" class="form-control">
<div class="card-body">
<div class="mb-4">
<h5 class="text-primary border-bottom mb-3 pb-2">Personal Information</h5>
<div class="row mb-3">
<div class="col-md-6">
<div class="form-group">
<label for="fullname">Fullname <span class="text-danger">*</span></label>
<input type="text" id="fullname" name="fullname" value="{{ old('fullname') }}"
class="form-control" required placeholder="Enter fullname">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="company">Company</label>
<input type="text" id="company" name="company" value="{{ old('company') }}"
class="form-control" placeholder="Enter company name">
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-md-6">
<div class="form-group">
<label for="email">Email Address <span class="text-danger">*</span></label>
<input type="email" id="email" name="email" value="{{ old('email') }}"
class="form-control" required placeholder="Enter email address">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="phone">Phone Number</label>
<input type="text" id="phone" name="phone" value="{{ old('phone') }}"
class="form-control" placeholder="(+84) 123. 456. 789">
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-md-12">
<div class="form-group">
<label for="password">Password <span class="text-danger">*</span></label>
<input type="password" id="password" name="password" class="form-control" required placeholder="******">
</div>
</div>
</div>
</div>
{{--City--}}
<div class="form-group row">
<label class="col-md-4" for="city">City</label>
<div class="col-md-8">
<input type="text" id="city" name="city" placeholder="City"
value="{{ old('city') }}" class="form-control">
<div class="mb-4">
<h5 class="text-primary border-bottom mb-3 pb-2">Address Information</h5>
<div class="row mb-3">
<div class="col-md-12">
<div class="form-group">
<label for="address">Address</label>
<input type="text" id="address" name="address" value="{{ old('address') }}"
class="form-control" placeholder="Enter address">
</div>
</div>
</div>
</div>
{{--State--}}
<div class="form-group row">
<label class="col-md-4" for="state">State</label>
<div class="col-md-8">
<input type="text" id="state" name="state" placeholder="State"
value="{{ old('state') }}" class="form-control">
<div class="row mb-3">
<div class="col-md-6">
<div class="form-group">
<label for="city">City</label>
<input type="text" id="city" name="city" value="{{ old('city') }}"
class="form-control" placeholder="Enter city">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="state">State</label>
<input type="text" id="state" name="state" value="{{ old('state') }}"
class="form-control" placeholder="Enter state">
</div>
</div>
</div>
</div>
{{--Postcode--}}
<div class="form-group row">
<label class="col-md-4" for="postcode">Postcode</label>
<div class="col-md-8">
<input type="text" id="postcode" name="postcode" placeholder="Postcode"
value="{{ old('postcode') }}" class="form-control">
</div>
</div>
{{--Country--}}
<div class="form-group row">
<label class="col-md-4" for="country">Country</label>
<div class="col-md-8">
<input type="text" id="country" name="country" placeholder="Country"
value="{{ old('country') }}" class="form-control">
</div>
</div>
{{--Password--}}
<div class="form-group row">
<label class="col-md-4" for="email_marketing">Marketing Emails Opt-in</label>
<div class="col-md-8">
<input type="checkbox" name="email_marketing" id="email_marketing" @checked(old('email_marketing') === "on")>
Send Client Marketing Emails
<div class="row mb-3">
<div class="col-md-6">
<div class="form-group">
<label for="postcode">Postcode</label>
<input type="text" id="postcode" name="postcode" value="{{ old('postcode') }}"
class="form-control" placeholder="Enter postcode">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="country">Country</label>
<input type="text" id="country" name="country" value="{{ old('country') }}"
class="form-control" placeholder="Enter country">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card-footer">
<button type="submit" class="btn btn-outline-primary">Save</button>
</div>
</form>
</div>
<div class="col-md-4 sticky-top top-10 z-0">
<div class="card card-secondary card-outline mb-3 rounded-4 shadow-none">
<div class="card-header rounded-top-4">
<h5 class="card-title m-0">Settings</h5>
</div>
<div class="card-body">
<div class="form-group mb-3">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="email_marketing"
name="email_marketing" value="1" {{ old('email_marketing') === "on" ? 'checked' : '' }}>
<label class="form-check-label" for="email_marketing">Marketing Emails Opt-in</label>
</div>
<small class="text-muted">Send client marketing emails</small>
</div>
</div>
</div>
</div>
</div>
<x-fixed-action-bar>
<x-button-crm type="button" variant="secondary" size="sm" icon="arrow-left"
route="customer.index">Cancel</x-button-crm>
<x-button-crm type="submit" variant="primary" size="sm" icon="plus-circle">Create Customer</x-button-crm>
</x-fixed-action-bar>
</form>
@else
<div class="alert alert-danger alert-dismissible">
<h5 class="mb-0"><i class="icon fas fa-ban"></i> Access Denied - You are not assigned to any Customer
management department</h5>
<h5 class="mb-0"><i class="icon fas fa-ban"></i> Access Denied - You are not assigned to any Customer management department</h5>
</div>
@endif
@endsection
@@ -1,116 +1,153 @@
@extends("administrator.layout.master")
@section("content")
@extends('administrator.layout.master')
@push('plugin-styles')
@foreach (config('assets.datatable.css') as $datatable)
<link href="{{ asset($datatable) }}" rel="stylesheet" />
@endforeach
@endpush
@section('breadcrumb')
@php
$breadcrumbItems = [
['label' => 'Customer'],
['label' => 'Customer Management', 'url' => route('customer.index')],
['label' => 'Edit Customer', 'active' => true],
];
@endphp
<x-admin-breadcrumb :items="$breadcrumbItems" />
@endsection
@section('content')
@if(auth()->guard('admins')->user()->can("edit customer"))
<div class="card card-outline card-primary">
<form action="{{ route('customer.update', ['id' => $customer->id]) }}" method="post">
@csrf
@method('PUT')
<div class="card-body">
<div class="row">
<div class="col">
{{--Fullname--}}
<div class="form-group row">
<label class="col-md-4" for="fullname">Fullname</label>
<div class="col-md-8">
<input type="text" id="fullname" name="fullname" placeholder="Fullname"
value="{{ old('fullname', $customer->fullname) }}" class="form-control">
</div>
</div>
{{--Company--}}
<div class="form-group row">
<label class="col-md-4" for="company">Company</label>
<div class="col-md-8">
<input type="text" id="company" name="company" placeholder="Company"
value="{{ old('company', $customer->company) }}" class="form-control">
</div>
</div>
{{--Email--}}
<div class="form-group row">
<label class="col-md-4" for="email">Email Address</label>
<div class="col-md-8">
<input type="email" id="email" name="email" placeholder="Email Address"
value="{{ old('email', $customer->email) }}" class="form-control">
</div>
</div>
{{--Phone--}}
<div class="form-group row">
<label class="col-md-4" for="phone">Phone Number</label>
<div class="col-md-8">
<input type="text" id="phone" name="phone" placeholder="(+84) 123. 456. 789)"
value="{{ old('phone', $customer->phone) }}" class="form-control">
</div>
</div>
{{--Password--}}
<div class="form-group row">
<label class="col-md-4" for="password">Password (leave blank to keep current)</label>
<div class="col-md-8">
<input type="password" id="password" name="password" placeholder="******"
value="" class="form-control">
</div>
</div>
<form action="{{ route('customer.update', ['id' => $customer->id]) }}" method="post">
@csrf
@method('PUT')
<div class="row align-items-start">
<div class="col-md-8">
<div class="card card-primary card-outline rounded-4 shadow-none">
<div class="card-header rounded-top-4">
<h5 class="card-title m-0">Basic Information</h5>
</div>
<div class="col">
{{--Address--}}
<div class="form-group row">
<label class="col-md-4" for="address">Address</label>
<div class="col-md-8">
<input type="text" id="address" name="address" placeholder="Address"
value="{{ old('address', $customer->address) }}" class="form-control">
<div class="card-body">
<div class="mb-4">
<h5 class="text-primary border-bottom mb-3 pb-2">Personal Information</h5>
<div class="row mb-3">
<div class="col-md-6">
<div class="form-group">
<label for="fullname">Fullname <span class="text-danger">*</span></label>
<input type="text" id="fullname" name="fullname" value="{{ old('fullname', $customer->fullname) }}"
class="form-control" required placeholder="Enter fullname">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="company">Company</label>
<input type="text" id="company" name="company" value="{{ old('company', $customer->company) }}"
class="form-control" placeholder="Enter company name">
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-md-6">
<div class="form-group">
<label for="email">Email Address <span class="text-danger">*</span></label>
<input type="email" id="email" name="email" value="{{ old('email', $customer->email) }}"
class="form-control" required placeholder="Enter email address">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="phone">Phone Number</label>
<input type="text" id="phone" name="phone" value="{{ old('phone', $customer->phone) }}"
class="form-control" placeholder="(+84) 123. 456. 789">
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-md-12">
<div class="form-group">
<label for="password">Password (leave blank to keep current)</label>
<input type="password" id="password" name="password" class="form-control" placeholder="******">
</div>
</div>
</div>
</div>
{{--City--}}
<div class="form-group row">
<label class="col-md-4" for="city">City</label>
<div class="col-md-8">
<input type="text" id="city" name="city" placeholder="City"
value="{{ old('city', $customer->city) }}" class="form-control">
<div class="mb-4">
<h5 class="text-primary border-bottom mb-3 pb-2">Address Information</h5>
<div class="row mb-3">
<div class="col-md-12">
<div class="form-group">
<label for="address">Address</label>
<input type="text" id="address" name="address" value="{{ old('address', $customer->address) }}"
class="form-control" placeholder="Enter address">
</div>
</div>
</div>
</div>
{{--State--}}
<div class="form-group row">
<label class="col-md-4" for="state">State</label>
<div class="col-md-8">
<input type="text" id="state" name="state" placeholder="State"
value="{{ old('state', $customer->state) }}" class="form-control">
<div class="row mb-3">
<div class="col-md-6">
<div class="form-group">
<label for="city">City</label>
<input type="text" id="city" name="city" value="{{ old('city', $customer->city) }}"
class="form-control" placeholder="Enter city">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="state">State</label>
<input type="text" id="state" name="state" value="{{ old('state', $customer->state) }}"
class="form-control" placeholder="Enter state">
</div>
</div>
</div>
</div>
{{--Postcode--}}
<div class="form-group row">
<label class="col-md-4" for="postcode">Postcode</label>
<div class="col-md-8">
<input type="text" id="postcode" name="postcode" placeholder="Postcode"
value="{{ old('postcode', $customer->postcode) }}" class="form-control">
</div>
</div>
{{--Country--}}
<div class="form-group row">
<label class="col-md-4" for="country">Country</label>
<div class="col-md-8">
<input type="text" id="country" name="country" placeholder="Country"
value="{{ old('country', $customer->country) }}" class="form-control">
</div>
</div>
{{--Marketing Emails--}}
<div class="form-group row">
<label class="col-md-4" for="email_marketing">Marketing Emails Opt-in</label>
<div class="col-md-8">
<input type="checkbox" name="email_marketing" id="email_marketing" @checked(old('email_marketing', $customer->email_marketing) == 1)>
Send Client Marketing Emails
<div class="row mb-3">
<div class="col-md-6">
<div class="form-group">
<label for="postcode">Postcode</label>
<input type="text" id="postcode" name="postcode" value="{{ old('postcode', $customer->postcode) }}"
class="form-control" placeholder="Enter postcode">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="country">Country</label>
<input type="text" id="country" name="country" value="{{ old('country', $customer->country) }}"
class="form-control" placeholder="Enter country">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card-footer">
<button type="submit" class="btn btn-outline-primary">Update</button>
</div>
</form>
</div>
<div class="col-md-4 sticky-top top-10 z-0">
<div class="card card-secondary card-outline mb-3 rounded-4 shadow-none">
<div class="card-header rounded-top-4">
<h5 class="card-title m-0">Settings</h5>
</div>
<div class="card-body">
<div class="form-group mb-3">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="email_marketing"
name="email_marketing" value="1" {{ old('email_marketing', $customer->email_marketing) == 1 ? 'checked' : '' }}>
<label class="form-check-label" for="email_marketing">Marketing Emails Opt-in</label>
</div>
<small class="text-muted">Send client marketing emails</small>
</div>
</div>
</div>
</div>
</div>
<x-fixed-action-bar>
<x-button-crm type="button" variant="secondary" size="sm" icon="arrow-left"
route="customer.index">Cancel</x-button-crm>
<x-button-crm type="submit" variant="primary" size="sm" icon="save">Update Customer</x-button-crm>
</x-fixed-action-bar>
</form>
@else
<div class="alert alert-danger alert-dismissible">
<h5 class="mb-0"><i class="icon fas fa-ban"></i> Access Denied - You are not assigned to any Customer
management department</h5>
<h5 class="mb-0"><i class="icon fas fa-ban"></i> Access Denied - You are not assigned to any Customer management department</h5>
</div>
@endif
@endsection
@@ -221,16 +221,21 @@
</div>
{{-- Product Type --}}
<div class="form-group mb-3">
<label for="product_type" class="mb-2">Product Type</label>
<select class="form-control select2" name="product_type" id="product_type">
<option value="">-- Select Type --</option>
<label class="mb-2">Product Type</label>
<div class="row">
@foreach (\App\Enums\Product\ProductTypeEnums::cases() as $type)
<option value="{{ $type->value }}"
{{ old('product_type') == $type->value ? 'selected' : '' }}>
{{ $type->label() }}
</option>
<div class="col-md-6 mb-2">
<div class="form-check">
<input class="form-check-input" type="radio" name="product_type"
id="product_type_{{ $type->value }}" value="{{ $type->value }}"
{{ old('product_type') == $type->value ? 'checked' : '' }}>
<label class="form-check-label" for="product_type_{{ $type->value }}">
{{ $type->label() }}
</label>
</div>
</div>
@endforeach
</select>
</div>
</div>
{{-- Operating System (for VPS) --}}
<div class="form-group mb-3" id="os-section">
@@ -289,14 +294,11 @@
{{-- Status --}}
<div class="form-group mb-3">
<label for="is_active" class="mb-2">Status</label>
<select class="form-control select2" name="is_active" id="is_active">
@foreach (\App\Enums\Status::cases() as $status)
<option value="{{ $status->value }}"
{{ old('is_active', \App\Enums\Status::ACTIVE->value) == $status->value ? 'selected' : '' }}>
{{ $status->label() }}
</option>
@endforeach
</select>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="is_active"
name="is_active" value="1" {{ old('is_active', true) ? 'checked' : '' }}>
<label class="form-check-label" for="is_active">Active</label>
</div>
</div>
<div class="form-group mb-3">
@@ -350,13 +352,16 @@
@endforeach
<script>
$(document).ready(function() {
// Initialize Select2 FIRST
if ($(".select2").length) {
$(".select2").select2();
$(".select2").select2({
allowClear: true
});
}
// Toggle OS/Control Panel sections based on Product Type
function toggleProductSections() {
const productType = $('#product_type').val();
const productType = $('input[name="product_type"]:checked').val();
if (productType === 'hosting') {
$('#os-section').hide();
@@ -394,7 +399,7 @@
toggleProductSections();
// Toggle when product type changes
$('#product_type').on('change', toggleProductSections);
$('input[name="product_type"]').on('change', toggleProductSections);
// Trigger initial panel price display
$('#control_panel_ids').trigger('change');