optimize dockerfile and copy js library used
This commit is contained in:
@@ -154,5 +154,289 @@
|
||||
@endsection
|
||||
|
||||
@section('javascripts')
|
||||
<script src="{{ mix('js/warehouse_management/mutations/create.js') }}"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
let productIndex = 1;
|
||||
let originalProductOptions = ""; // Store original product options
|
||||
|
||||
// Initialize Select2
|
||||
$(".select2").select2({
|
||||
placeholder: "Pilih...",
|
||||
allowClear: true,
|
||||
});
|
||||
|
||||
// Store original product options on page load
|
||||
const firstSelect = $(".product-select").first();
|
||||
if (firstSelect.length > 0) {
|
||||
originalProductOptions = firstSelect.html();
|
||||
}
|
||||
|
||||
// Prevent same dealer selection
|
||||
$("#from_dealer_id, #to_dealer_id").on("change", function () {
|
||||
const fromDealerId = $("#from_dealer_id").val();
|
||||
const toDealerId = $("#to_dealer_id").val();
|
||||
|
||||
if (fromDealerId && toDealerId && fromDealerId === toDealerId) {
|
||||
$(this).val("").trigger("change");
|
||||
Swal.fire({
|
||||
type: "error",
|
||||
title: "Oops...",
|
||||
text: "Dealer asal dan tujuan tidak boleh sama",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update available stock when dealer changes
|
||||
updateAllAvailableStock();
|
||||
});
|
||||
|
||||
// Add new product row
|
||||
$("#add-product").on("click", function () {
|
||||
const newRow = createProductRow(productIndex);
|
||||
$("#products-tbody").append(newRow);
|
||||
|
||||
// Initialize Select2 for new row after it's added to DOM
|
||||
const newSelect = $(
|
||||
`#products-tbody tr[data-index="${productIndex}"] .product-select`
|
||||
);
|
||||
newSelect.select2({
|
||||
placeholder: "Pilih...",
|
||||
allowClear: true,
|
||||
});
|
||||
|
||||
productIndex++;
|
||||
updateRemoveButtons();
|
||||
});
|
||||
|
||||
// Remove product row
|
||||
$(document).on("click", ".remove-product", function () {
|
||||
$(this).closest("tr").remove();
|
||||
updateRemoveButtons();
|
||||
reindexRows();
|
||||
});
|
||||
|
||||
// Handle product selection change
|
||||
$(document).on("change", ".product-select", function () {
|
||||
const row = $(this).closest("tr");
|
||||
const productId = $(this).val();
|
||||
const fromDealerId = $("#from_dealer_id").val();
|
||||
|
||||
if (productId && fromDealerId) {
|
||||
getAvailableStock(productId, fromDealerId, row);
|
||||
} else {
|
||||
row.find(".available-stock").text("-");
|
||||
row.find(".quantity-input").attr("max", "");
|
||||
}
|
||||
});
|
||||
|
||||
// Validate quantity input
|
||||
$(document).on("input", ".quantity-input", function () {
|
||||
const maxValue = parseFloat($(this).attr("max"));
|
||||
const currentValue = parseFloat($(this).val());
|
||||
|
||||
if (maxValue && currentValue > maxValue) {
|
||||
$(this).val(maxValue);
|
||||
$(this).addClass("is-invalid");
|
||||
|
||||
if (!$(this).siblings(".invalid-feedback").length) {
|
||||
$(this).after(
|
||||
'<div class="invalid-feedback">Quantity melebihi stock yang tersedia</div>'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$(this).removeClass("is-invalid");
|
||||
$(this).siblings(".invalid-feedback").remove();
|
||||
}
|
||||
});
|
||||
|
||||
// Form submission
|
||||
$("#mutation-form").on("submit", function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!validateForm()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const submitBtn = $("#submit-btn");
|
||||
const originalText = submitBtn.html();
|
||||
|
||||
submitBtn
|
||||
.prop("disabled", true)
|
||||
.html('<i class="la la-spinner la-spin"></i> Menyimpan...');
|
||||
|
||||
// Submit form
|
||||
this.submit();
|
||||
});
|
||||
|
||||
function createProductRow(index) {
|
||||
return `
|
||||
<tr class="product-row" data-index="${index}">
|
||||
<td>
|
||||
<select name="products[${index}][product_id]" class="form-control product-select" required>
|
||||
${originalProductOptions}
|
||||
</select>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<span class="available-stock text-muted">-</span>
|
||||
</td>
|
||||
<td>
|
||||
<input type="number"
|
||||
name="products[${index}][quantity_requested]"
|
||||
class="form-control quantity-input"
|
||||
min="0.01"
|
||||
step="0.01"
|
||||
placeholder="0"
|
||||
required>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<button type="button" class="btn btn-danger btn-sm remove-product">
|
||||
<i class="la la-trash"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
}
|
||||
|
||||
function updateRemoveButtons() {
|
||||
const rows = $(".product-row");
|
||||
$(".remove-product").prop("disabled", rows.length <= 1);
|
||||
}
|
||||
|
||||
function reindexRows() {
|
||||
$(".product-row").each(function (index) {
|
||||
$(this).attr("data-index", index);
|
||||
$(this)
|
||||
.find('select[name*="product_id"]')
|
||||
.attr("name", `products[${index}][product_id]`);
|
||||
$(this)
|
||||
.find('input[name*="quantity_requested"]')
|
||||
.attr("name", `products[${index}][quantity_requested]`);
|
||||
});
|
||||
productIndex = $(".product-row").length;
|
||||
}
|
||||
|
||||
function getAvailableStock(productId, dealerId, row) {
|
||||
$.ajax({
|
||||
url: "/warehouse/mutations/get-product-stock",
|
||||
method: "GET",
|
||||
data: {
|
||||
product_id: productId,
|
||||
dealer_id: dealerId,
|
||||
},
|
||||
beforeSend: function () {
|
||||
row.find(".available-stock").html(
|
||||
'<i class="la la-spinner la-spin"></i>'
|
||||
);
|
||||
},
|
||||
success: function (response) {
|
||||
const stock = parseFloat(response.current_stock);
|
||||
row.find(".available-stock").text(stock.toLocaleString());
|
||||
row.find(".quantity-input").attr("max", stock);
|
||||
|
||||
// Set max value message
|
||||
if (stock <= 0) {
|
||||
row.find(".available-stock")
|
||||
.addClass("text-danger")
|
||||
.removeClass("text-muted");
|
||||
row.find(".quantity-input").attr("readonly", true).val("");
|
||||
} else {
|
||||
row.find(".available-stock")
|
||||
.removeClass("text-danger")
|
||||
.addClass("text-muted");
|
||||
row.find(".quantity-input").attr("readonly", false);
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
row.find(".available-stock")
|
||||
.text("Error")
|
||||
.addClass("text-danger");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function updateAllAvailableStock() {
|
||||
const fromDealerId = $("#from_dealer_id").val();
|
||||
|
||||
$(".product-row").each(function () {
|
||||
const row = $(this);
|
||||
const productId = row.find(".product-select").val();
|
||||
|
||||
if (productId && fromDealerId) {
|
||||
getAvailableStock(productId, fromDealerId, row);
|
||||
} else {
|
||||
row.find(".available-stock").text("-");
|
||||
row.find(".quantity-input").attr("max", "");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function validateForm() {
|
||||
let isValid = true;
|
||||
const fromDealerId = $("#from_dealer_id").val();
|
||||
const toDealerId = $("#to_dealer_id").val();
|
||||
|
||||
// Check dealers
|
||||
if (!fromDealerId) {
|
||||
Swal.fire({
|
||||
type: "error",
|
||||
title: "Oops...",
|
||||
text: "Pilih dealer asal",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!toDealerId) {
|
||||
Swal.fire({
|
||||
type: "error",
|
||||
title: "Oops...",
|
||||
text: "Pilih dealer tujuan",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fromDealerId === toDealerId) {
|
||||
Swal.fire({
|
||||
type: "error",
|
||||
title: "Oops...",
|
||||
text: "Dealer asal dan tujuan tidak boleh sama",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check products
|
||||
const productRows = $(".product-row");
|
||||
if (productRows.length === 0) {
|
||||
Swal.fire({
|
||||
type: "error",
|
||||
title: "Oops...",
|
||||
text: "Tambahkan minimal satu produk",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
let hasValidProduct = false;
|
||||
productRows.each(function () {
|
||||
const productId = $(this).find(".product-select").val();
|
||||
const quantity = $(this).find(".quantity-input").val();
|
||||
|
||||
if (productId && quantity && parseFloat(quantity) > 0) {
|
||||
hasValidProduct = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!hasValidProduct) {
|
||||
Swal.fire({
|
||||
type: "error",
|
||||
title: "Oops...",
|
||||
text: "Pilih minimal satu produk dengan quantity yang valid",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
return isValid;
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
@endsection
|
||||
Reference in New Issue
Block a user