Files
gps-frontend/resources/views/menu_v1/clients.blade.php
meusinfirmary 8f57b5b72a updated
2025-06-01 21:14:58 +07:00

1419 lines
70 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@extends('app.app')
@section('title')
Clients
@endsection
@section('customcss')
<style>
.landscape-photo {
max-height: max(21vh, 210px);
}
/* .select2-container {
z-index: 99999;
} */
</style>
@endsection
@section('content')
<div class="container-fluid">
<div class="content">
<div class="row">
<div class="col-sm-12">
<div class="card">
<div class="card-header">
<div class="row d-flex align-items-center">
<div class="col">
<p class="card-title text-bold mb-0">Company</p>
</div>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table id="tClients" class="table table-hover dataTable w-100">
<thead>
<tr class="">
<th class="">#</th>
<th class="text-center">Action</th>
<th class="text-nowrap">Company Name</th>
<th class="text-nowrap">Company Address</th>
<th class="text-nowrap">Phone Number</th>
<th class="text-nowrap">Email Addres</th>
{{-- <th class="text-nowrap">Tanggal Bergabung</th> --}}
<th class="text-nowrap">Total Job</th>
<th class="text-nowrap">PIC Name</th>
<th class="text-nowrap">PIC Phone NUmber</th>
<th class="text-nowrap">PIC Email Address</th>
{{-- <th class="text-center">Status</th> --}}
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="col-sm-8"></div>
</div>
</div>
</div>
{{-- MODAL --}}
{{-- <div class="modal fade" id="addNewClientModal" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="false" aria-labelledby="addNewClientModal" aria-hidden="true">
<div class="modal-dialog modal-dialog modal-dialog-centered modal-dialog-scrollable modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="addNewClientModal">Tambah Client Baru</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body pb-0">
<div class="row">
<div class="col-sm-6">
<h6>Informasi Client</h6>
<div class="mb-3">
<label for="add-clogo" class="form-label">Logo</label>
<br>
<img id="add-clogo-img" class="img-fluid landscape-photo" src="{{ asset('images/swa-nusa-logo.png') }}" alt="add-clogo-img">
<div id="add-group_clogo_spinner" class="d-none">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
<div id="add-group_rotate_clogo" class="pt-2 d-flex justify-content-start d-none">
<button type="button" class="btnRotateLeft btn btn-sm btn-outline-primary ml-1" style="padding:0.25rem 0.5rem;border-radius:0.25rem;"><i class="icon ion-arrow-return-left"></i></button>
<button type="button" class="btnRotateRight btn btn-sm btn-outline-primary ml-1" style="padding:0.25rem 0.5rem;border-radius:0.25rem;"><i class="icon ion-arrow-return-right"></i></button>
</div>
<input type="file" id="add-clogo-file" class="form-control mt-3">
<input type="text" id="add-clogo-base64" class="form-control" hidden>
<div>
<span id="add-clogo-status"></span>
<span id="add-clogo-filesize"></span>
</div>
</div>
<div class="mb-3">
<label for="add-cname" class="form-label">Nama Client/Nama Perusahaan</label>
<input type="text" class="form-control form-control-sm" name="add-cname" id="add-cname">
</div>
<div class="mb-3">
<label for="add-caddress_office" class="form-label">Alamat Perusahaan</label>
<textarea name="add-caddress_office" id="add-caddress_office" class="form-control form-control-sm" rows="3"></textarea>
</div>
<div class="mb-3">
<label for="add-cphone" class="form-label">Nomor Telepon</label>
<input type="number" class="form-control form-control-sm" name="add-cphone" id="add-cphone">
</div>
<div class="mb-4">
<label for="add-cmail" class="form-label">Alamat Email</label>
<input type="mail" class="form-control form-control-sm" name="add-cmail" id="add-cmail">
</div>
</div>
<div class="col-sm-6">
<h6>Infomrasi PIC</h6>
<div class="mb-3">
<label for="add-picname" class="form-label">Nama PIC</label>
<input type="text" class="form-control form-control-sm" name="add-picname" id="add-picname">
</div>
<div class="mb-3">
<label for="add-picphone" class="form-label">Telepon PIC</label>
<input type="number" class="form-control form-control-sm" name="add-picphone" id="add-picphone" placeholder="without zero">
</div>
<div class="mb-3">
<label for="add-picmail" class="form-label">Alamat Email PIC</label>
<input type="mail" class="form-control form-control-sm" name="add-picmail" id="add-picmail">
</div>
<br>
<h6>Lainnya</h6>
<div class="mb-3">
<label for="add-cstatus" class="form-label">Status Client</label>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="add-cstatus">
<label class="form-check-label" for="add-cstatus"><span class="text-dark" id="add-ctxtStatus">Tidak Aktif</span></label>
</div>
</div>
<div class="mb-3">
<label for="add-ccredentials" class="form-label">Create Login Credential</label>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="add-ccredentials">
<label class="form-check-label" for="add-ccredentials">
<span class="text-dark">Yes, please create login credential for this
client</span>
</label>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-sm btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" id="btnSubmitNewClient" class="btn btn-sm btn-danger">Submit data</button>
<div id="add-btnSubmitNewClient" class="d-none">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div>
</div>
</div>
</div> --}}
<div class="modal fade" id="updtClientModal" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="false" aria-labelledby="updtClientModal" aria-hidden="true">
<div class="modal-dialog modal-dialog modal-dialog-centered modal-dialog-scrollable modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="updtClientModal">Company Data</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body pb-0">
<div class="row">
<div class="col-sm-6">
<h6>Company information</h6>
<div class="mb-3">
<label for="updt-clogo" class="form-label">Logo</label>
<br>
<img id="updt-clogo-img" class="img-fluid landscape-photo" src="{{ asset('images/swa-nusa-logo.png') }}" alt="updt-clogo-img">
<div id="updt-group_clogo_spinner" class="d-none">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
<div id="updt-group_rotate_clogo" class="pt-2 d-flex justify-content-start d-none">
<button type="button" class="btnRotateLeft btn btn-sm btn-outline-primary ml-1" style="pupdting:0.25rem 0.5rem;border-radius:0.25rem;"><i class="icon ion-arrow-return-left"></i></button>
<button type="button" class="btnRotateRight btn btn-sm btn-outline-primary ml-1" style="pupdting:0.25rem 0.5rem;border-radius:0.25rem;"><i class="icon ion-arrow-return-right"></i></button>
</div>
<input type="file" id="updt-clogo-file" class="form-control mt-3">
<input type="text" id="updt-clogo-base64" class="form-control" hidden>
<div>
<span id="updt-clogo-status"></span>
<span id="updt-clogo-filesize"></span>
</div>
</div>
<div class="mb-3">
<label for="updt-cname" class="form-label">Company Name</label>
<input type="text" class="form-control form-control-sm" name="updt-cname" id="updt-cname">
</div>
<div class="mb-3">
<label for="updt-caddress_office" class="form-label">Full Address</label>
<textarea name="updt-caddress_office" id="updt-caddress_office" class="form-control form-control-sm" rows="3"></textarea>
</div>
<div class="mb-3">
<label for="updt-cphone" class="form-label">Phone Number</label>
<input type="number" class="form-control form-control-sm" name="updt-cphone" id="updt-cphone">
</div>
<div class="mb-4">
<label for="updt-cmail" class="form-label">Email Account</label>
<input type="mail" class="form-control form-control-sm" name="updt-cmail" id="updt-cmail">
</div>
</div>
<div class="col-sm-6">
<h6>PIC Inforamation</h6>
<div class="mb-3">
<label for="updt-picname" class="form-label">PIC Name</label>
<input type="text" class="form-control form-control-sm" name="updt-picname" id="updt-picname">
</div>
<div class="mb-3">
<label for="updt-picphone" class="form-label">PIC Phone NUmber</label>
<input type="number" class="form-control form-control-sm" name="updt-picphone" id="updt-picphone" placeholder="without zero">
</div>
<div class="mb-3">
<label for="updt-picmail" class="form-label">PIC Email Account</label>
<input type="mail" class="form-control form-control-sm" name="updt-picmail" id="updt-picmail">
</div>
{{-- <br>
<h6>Diskon</h6>
<div class="mb-3">
<label for="updt-disc_type" class="form-label">Tipe Diskon</label>
<select id="updt-disc_type" class="form-control" style="width:100%;">
@foreach ($disc_types as $type)
<option value="{{ $type['id'] }}">
{{ $type['name'] }}
</option>
@endforeach
</select>
</div> --}}
{{-- <div id="updt-group_disc_amount" class="mb-3">
<label for="updt-disc_amount" class="form-label">Nilai Diskon</label>
<input type="number" class="form-control form-control-sm" name="updt-disc_amount" id="updt-disc_amount">
</div>
<br> --}}
<h6 class="d-none">Others</h6>
<div class="mb-3 d-none">
<label for="updt-cstatus" class="form-label">Status Client</label>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="updt-cstatus">
<label class="form-check-label" for="updt-cstatus"><span class="text-dark" id="updt-ctxtStatus">Inactive</span></label>
</div>
</div>
<div id="group-updt-ccredentials" class="mb-3">
<label for="updt-ccredentials" class="form-label">Create Login Credential</label>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="updt-ccredentials" checked>
<label class="form-check-label" for="updt-ccredentials" checked>
<span class="text-dark">Yes, please create login credential for this
client</span>
</label>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
{{-- <button type="button" id="btnDelClient_updt" class="btn btn-sm btn-warning">Delete ?</button> --}}
<button type="button" class="btn btn-sm btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" id="btnSubmitUpdtClient" class="btn btn-sm btn-danger">Update data</button>
<div id="edt-btnSubmitUpdtClient" class="d-none">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="delClientModal" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="false" aria-labelledby="delClientModal" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-sm">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="delClientModal">Delete Client</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="d-flex justify-content-center">
<p class="mb-0">
Are you sure want to delete this client
<a href="#" class="text-danger">
<span id="del-c_name"></span>
(<span id="del-c_phone"></span>)
</a>
</p>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-sm btn-danger" data-bs-dismiss="modal">Close</button>
<button id="btnSubmitDelClient" type="button" class="btn btn-sm btn-secondary">Yes, delete</button>
</div>
</div>
</div>
</div>
@endsection
@section('customjs')
<script src="{{ asset('assets/js/load-image.all.min.js') }}"></script>
<script>
'use strict';
const State = {
file_jimp_worker: "{{ asset('assets/js/worker/jimp.js') }}",
storage_lara: "{{ asset('storage') }}/",
client_status: {
active: "{{ App\Models\Clients::CSTTS_ACTIVE }}",
inactive: "{{ App\Models\Clients::CSTTS_INACTIVE }}",
},
ccredentials: {
create: "{{ App\Models\Clients::CCREDENTIALS_CREATE }}",
not: "{{ App\Models\Clients::CCREDENTIALS_NOT }}",
},
discount_type: {
no: "{{ App\Models\Clients::DISC_TYPE_NO }}",
}
};
const Wrapper = {
activate: function() {
Wrapper.event();
DTable.activate();
CNew.activate();
CUpdate.activate();
CDel.activate();
Filter.activate();
// new images
CUploadAdd.activate('clogo');
// update images
CUploadUpdt.activate('clogo');
},
event: function() {
$('#add-cstatus').bind('change', function() {
if ($(this).is(':checked'))
$('#add-ctxtStatus').html('Aktif')
else
$('#add-ctxtStatus').html('Tidak Aktif')
});
$('#updt-cstatus').bind('change', function() {
if ($(this).is(':checked'))
$('#updt-ctxtStatus').html('Active')
else
$('#updt-ctxtStatus').html('Inactive')
});
$('#add-disc_type').on('change', function() {
if ($(this).val() == State.discount_type.no) {
$('#add-group_disc_amount').addClass('d-none');
} else {
$('#add-group_disc_amount').removeClass('d-none');
}
});
$('#updt-disc_type').on('change', function() {
if ($(this).val() == State.discount_type.no) {
$('#updt-group_disc_amount').addClass('d-none');
} else {
$('#updt-group_disc_amount').removeClass('d-none');
}
});
$('#add-disc_type').select2({
dropdownParent: $('#addNewClientModal'),
});
$('#updt-disc_type').select2({
dropdownParent: $('#updtClientModal'),
});
},
};
const DTable = {
activate: function() {
DTable.reload();
},
reload: function() {
// $('#tClients').DataTable();
// if (Client.Table.firstInitDataTable == 1) { loadTableSkeletonLoading() } else { Client.Table.firstInitDataTable = 1; }
$('#tClients').DataTable({
processing: true,
serverSide: false,
bLengthChange: true,
deferRender: true,
destroy: true,
ajax: {
url: "{{ route('api_list_clients') }}?cptid=" + AppState.current_company,
type: 'GET',
complete: function(jqXHR, textStatus, c) {
let count = jqXHR.responseJSON.count;
if (typeof count != 'undefined') {
$('#count_clients').text(count);
}
// removeTableSkeletonLoading()
},
},
deferRender: true,
columns: [{
data: 'DT_RowIndex',
className: 'text-end',
visible: true,
orderable: true,
searchable: true,
},
{
data: 'action',
className: 'text-center',
visible: true,
orderable: true,
searchable: true,
render: function(data, type, row, meta) {
// <a href="#" class="text-decoration-none me-1 btnViewClient" data-bs-toggle="tooltip"
// data-bs-placement="bottom" title="View">
// <span class="icon ion-eye fz-16"></span>
// </a>
let action = `
<a href="#" class="text-decoration-none me-1 btnEdtClient" data-bs-toggle="tooltip"
data-bs-placement="bottom" title="Edit">
<span class="icon ion-edit fz-16"></span>
</a>
`;
// <a href="#" class="text-decoration-none text-danger btnDelClient"
// data-bs-toggle="tooltip" data-bs-placement="bottom" title="Delete">
// <span class="icon ion-trash-b fz-16"></span>
// </a>
return action;
}
},
{
data: 'c_name',
className: 'text-start',
visible: true,
orderable: true,
searchable: true,
createdCell: function(td, cellData, rowData, row, col) {
$(td).attr('data-id', rowData.client_id);
$(td).attr('data-c_name', rowData.c_name);
$(td).attr('data-c_phone', rowData.c_phone);
$(td).attr('data-c_phone_code', rowData.c_phone_code);
},
},
{
data: 'c_addr_office',
className: 'text-start',
visible: true,
orderable: true,
searchable: true,
},
{
data: 'c_phone',
className: 'text-start text-nowrap',
visible: true,
orderable: true,
searchable: true,
render: function(data, type, row, meta) {
return (
`<a href="tel:0${data}"><i class="text-dark ion-ios-telephone"></i> ${Helper.splitEvery4Char('0'+data)}</a>` +
`<br>` +
`<a href="https://api.whatsapp.com/send/?phone=62${data}&text=Halo&app_absent=0" target="_blank"><i class="text-success ion-social-whatsapp"></i> ${Helper.splitEvery4Char('0'+data)}</a>`
);
},
},
{
data: 'c_mail',
className: 'text-start text-nowrap',
visible: true,
orderable: true,
searchable: true,
},
{
data: 'count_trx',
className: 'text-end text-nowrap',
visible: true,
orderable: true,
searchable: true,
},
{
data: 'pic_name',
className: 'text-start text-nowrap',
visible: true,
orderable: true,
searchable: true,
},
{
data: 'pic_phone',
className: 'text-end text-nowrap',
visible: true,
orderable: true,
searchable: true,
render: function(data, type, row, meta) {
return (
`<a href="tel:0${data}"><i class="text-dark ion-ios-telephone"></i> ${Helper.splitEvery4Char('0'+data)}</a>` +
`<br>` +
`<a href="https://api.whatsapp.com/send/?phone=62${data}&text=Halo&app_absent=0" target="_blank"><i class="text-success ion-social-whatsapp"></i> ${Helper.splitEvery4Char('0'+data)}</a>`
);
},
},
{
data: 'pic_mail',
className: 'text-start text-nowrap',
visible: true,
orderable: true,
searchable: true,
},
/*{
data: 'c_status',
className: 'text-center',
visible: true,
orderable: true,
searchable: true,
render: function(data, type, row, meta) {
if (data == State.client_status.active) {
return '<span class="badge rounded-pill bg-success">Active</span>';
}
return '<span class="badge rounded-pill bg-danger">Inactive</span>';
},
},*/
],
});
},
};
const CNew = {
activate: function() {
CNew.event();
},
event: function() {
// modal
$('#btnAddNewClientModal').on('click', function() {
$('#addNewClientModal').modal('show');
});
$('#addNewClientModal').on('shown.bs.modal', function() {
// initiate select2 if there
$('#add-ccredentials').prop('checked', false);
});
$('#btnSubmitNewClient').on('click', function() {
let data = CNew.getData();
CNew.submitData(data);
});
},
getData: function() {
let data = {};
data.clogo_base64 = $('#add-clogo-base64').val().replace(/^data:image\/(png|jpg|jpeg);base64,/, '');
data.cname = $('#add-cname').val();
data.caddress_office = $('#add-caddress_office').val();
data.cphone = $('#add-cphone').val();
data.cmail = $('#add-cmail').val();
data.picname = $('#add-picname').val();
data.picphone = $('#add-picphone').val();
data.picmail = $('#add-picmail').val();
data.disc_type = $('#add-disc_type').val();
if (data.disc_type == State.discount_type.no) {
data.disc_amount = 0;
} else {
data.disc_amount = $('#add-disc_amount').val();
}
if ($('#add-cstatus').prop('checked')) {
data.cstatus = State.client_status.active;
} else {
data.cstatus = State.client_status.inactive;
}
if ($('#add-ccredentials').prop('checked')) {
data.ccredentials = State.ccredentials.create;
} else {
data.ccredentials = State.ccredentials.not;
}
return data;
},
submitData: async function(data) {
return new Promise((resolve, reject) => {
if (typeof $('#btnSubmitNewClient').attr('disabed') != 'undefined') {
resolve({
type: 'fail'
});
return false;
}
$('#btnSubmitNewClient').attr('disabed', true);
$('#btnSubmitNewClient').addClass('d-none');
$('#add-btnSubmitNewClient').removeClass('d-none');
$.ajax({
url: "{{ route('api_add_client') }}",
method: 'POST',
crossDomain: true,
processData: true,
headers: {
'x-api-key': Helper.getCookie('_trtk'),
'x-csrf-token': $('meta[name="csrf-token"]').attr('content'),
},
data: data,
success: (data, textStatus, jqXHR) => {
$('#btnSubmitNewClient').removeAttr('disabed');
$('#btnSubmitNewClient').removeClass('d-none');
$('#add-btnSubmitNewClient').addClass('d-none');
if (data.meta.type != 'success') {
resolve({
type: 'fail'
});
Helper.toast('Warning', 'just now', data.meta.message);
return false;
}
Helper.toast('Success', 'just now', 'success add new client');
$('#addNewClientModal').modal('hide');
DTable.reload();
resolve({
type: 'success'
});
},
error: (jqXHR, textStatus, error) => {
$('#btnSubmitNewClient').removeAttr('disabed');
$('#btnSubmitNewClient').removeClass('d-none');
$('#add-btnSubmitNewClient').addClass('d-none');
if (jqXHR.status >= 500) {
Helper.toast('Error', 'just now', 'please try again');
} else {
Helper.toast('Error', 'just now', jqXHR.responseJSON.meta
.message);
}
resolve({
type: 'error'
});
}
})
})
},
}
const CUpdate = {
activate: function() {
CUpdate.event();
},
event: function() {
// modal
$('#tClients').on('click', '.btnEdtClient', async function(e) {
let cid = $(e.target).closest('tr').find('td[data-id]').data('id');
let resp = await CUpdate.reqData({
cid
});
if (resp.type != 'success') {
Helper.toast('Client Not Found', 'just now', 'please try again');
return false;
}
CUpdate.passDataToView(resp.data);
});
$('#updtClientModal').on('shown.bs.modal', function() {
// initiate select2 if there
});
$('#btnSubmitUpdtClient').on('click', function() {
let data = CUpdate.getData();
CUpdate.submitData(data);
});
},
reqData: function(params) {
return new Promise((resolve, reject) => {
$.ajax({
url: "{{ route('api_show_client', '') }}/" + params.cid,
method: 'GET',
crossDomain: true,
processData: true,
headers: {
'x-api-key': Helper.getCookie('_trtk'),
},
data: params,
success: (data, textStatus, jqXHR) => {
if (data.meta.type != 'success') {
resolve({
type: 'fail'
});
Helper.toast('Warning', 'just now', data.meta.message);
return false;
}
resolve({
type: 'success',
data: data.data
});
},
error: (jqXHR, textStatus, error) => {
if (jqXHR.status >= 500) {
Helper.toast('Error', 'just now', 'please try again');
} else {
Helper.toast('Error', 'just now', jqXHR.responseJSON.meta
.message);
}
resolve({
type: 'error'
});
}
})
});
},
passDataToView: function(data) {
$('#updt-clogo-img').attr('src', State.storage_lara + data?.c_logo);
$('#updt-cname').val(data.c_name);
$('#updt-caddress_office').val(data.c_addr_office);
$('#updt-cphone').val(data.c_phone);
$('#updt-cmail').val(data.c_mail);
$('#updt-picname').val(data.pic_name);
$('#updt-picphone').val(data.pic_phone);
$('#updt-picmail').val(data.pic_mail);
$('#updt-disc_type').val(data.disc_type).trigger('change');
$('#updt-disc_amount').val(data.disc_amount);
if (data.c_status == State.client_status.active) {
$('#updt-cstatus').prop('checked', true).trigger('change');
} else {
$('#updt-cstatus').prop('checked', false).trigger('change');
}
if (data.c_credentials == State.ccredentials.create) { // has been created
$('#group-updt-ccredentials').addClass('d-none');
$('#updt-ccredentials').prop('checked', true).trigger('change');
} else { // hasn't created, so can create credentials
$('#group-updt-ccredentials').removeClass('d-none');
$('#updt-ccredentials').prop('checked', false).trigger('change');
}
$('#updtClientModal').data('cid', data.client_id);
$('#updtClientModal').modal('show');
},
getData: function() {
let data = {};
data.cid = $('#updtClientModal').data('cid');
let clogo = $('#updt-clogo-img').attr('src');
if (clogo.indexOf('clients/') > -1 && clogo.indexOf('logo_') > -1) {
data.clogo_base64 = 'noupdate';
} else {
data.clogo_base64 = $('#updt-clogo-base64').val().replace(/^data:image\/(png|jpg|jpeg);base64,/,
'');
}
data.cname = $('#updt-cname').val();
data.caddress_office = $('#updt-caddress_office').val();
data.cphone = $('#updt-cphone').val();
data.cmail = $('#updt-cmail').val();
data.picname = $('#updt-picname').val();
data.picphone = $('#updt-picphone').val();
data.picmail = $('#updt-picmail').val();
data.disc_type = $('#updt-disc_type').val();
if (data.disc_type == State.discount_type.no) {
data.disc_amount = 0;
} else {
data.disc_amount = $('#updt-disc_amount').val();
}
if ($('#updt-cstatus').prop('checked')) {
data.cstatus = State.client_status.active;
} else {
data.cstatus = State.client_status.inactive;
}
if ($('#updt-ccredentials').prop('checked')) {
data.ccredentials = State.ccredentials.create;
} else {
data.ccredentials = State.ccredentials.not;
}
return data;
},
submitData: async function(data) {
return new Promise((resolve, reject) => {
if (typeof $('#btnSubmitUpdtClient').attr('disabed') != 'undefined') {
resolve({
type: 'fail'
});
return false;
}
$('#btnSubmitUpdtClient').attr('disabed', true);
$('#btnSubmitUpdtClient').addClass('d-none');
$('#edt-btnSubmitUpdtClient').removeClass('d-none');
$.ajax({
url: "{{ route('api_edit_client', '') }}/" + data.cid,
method: 'PUT',
crossDomain: true,
processData: true,
headers: {
'x-csrf-token': $('meta[name="csrf-token"]').attr('content'),
'x-api-key': Helper.getCookie('_trtk'),
},
data: data,
success: (data, textStatus, jqXHR) => {
$('#btnSubmitUpdtClient').removeAttr('disabed');
$('#btnSubmitUpdtClient').removeClass('d-none');
$('#edt-btnSubmitUpdtClient').addClass('d-none');
if (data.meta.type != 'success') {
resolve({
type: 'fail'
});
Helper.toast('Warning', 'just now', data.meta.message);
return false;
}
Helper.toast('Success', 'just now', 'success update client');
$('#updtClientModal').modal('hide');
DTable.reload();
resolve({
type: 'success'
});
},
error: (jqXHR, textStatus, error) => {
$('#btnSubmitUpdtClient').removeAttr('disabed');
$('#btnSubmitUpdtClient').removeClass('d-none');
$('#edt-btnSubmitUpdtClient').addClass('d-none');
if (jqXHR.status >= 500) {
Helper.toast('Error', 'just now', 'please try again');
} else {
Helper.toast('Error', 'just now', jqXHR.responseJSON.meta
.message);
}
resolve({
type: 'error'
});
}
})
});
},
}
const CDel = {
activate: function() {
CDel.event();
},
event: function() {
// on table
$('#tClients').on('click', '.btnDelClient', function(e) {
let row = $(e.target).closest('tr');
let cid = row.find('td[data-id]').data('id');
let c_name = row.find('td[data-c_name]').data('c_name');
let c_phone = row.find('td[data-c_phone]').data('c_phone');
let c_phone_code = row.find('td[data-c_phone_code]').data('c_phone_code');
CDel.passDataToView({
cid,
c_name,
c_phone,
c_phone_code,
});
$('#delClientModal').data('id', cid);
$('#delClientModal').modal('show');
});
$('#btnSubmitDelClient').on('click', function() {
let data = {
cid: $('#delClientModal').data('id'),
};
CDel.submitData(data);
});
// on modal update
$('#btnDelClient_updt').on('click', function(e) {
let data = CUpdate.getData();
CDel.passDataToView({
cid: data.cid,
c_name: data.cname,
c_phone: data.cphone,
c_phone_code: 62,
});
$('#delClientModal').data('id', data.cid);
$('#delClientModal').modal('show');
});
},
passDataToView: function(data) {
data.c_phone = '' + data.c_phone
$('#del-c_name').text(data.c_name);
$('#del-c_phone').text(`+${data.c_phone_code} ${Helper.splitEvery4Char(data.c_phone)}`);
},
submitData: async function(data) {
return new Promise((resolve, reject) => {
if (typeof $('#btnSubmitDelClient').attr('disabed') != 'undefined') {
resolve({
type: 'fail'
});
return false;
}
$('#btnSubmitDelClient').attr('disabed', true);
$.ajax({
url: "{{ route('api_del_client', '') }}/" + data.cid,
method: 'DELETE',
crossDomain: true,
processData: true,
headers: {
'x-csrf-token': $('meta[name="csrf-token"]').attr('content'),
'x-api-key': Helper.getCookie('_trtk'),
},
data: data,
success: (data, textStatus, jqXHR) => {
$('#btnSubmitDelClient').removeAttr('disabed');
if (data.meta.type != 'success') {
resolve({
type: 'fail'
});
Helper.toast('Warning', 'just now', data.meta.message);
return false;
}
Helper.toast('Success', 'just now', 'success delete client');
$('#delClientModal').modal('hide');
$('#updtClientModal').modal('hide');
DTable.reload();
resolve({
type: 'success'
});
},
error: (jqXHR, textStatus, error) => {
$('#btnSubmitDelClient').removeAttr('disabed');
if (jqXHR.status >= 500) {
Helper.toast('Error', 'just now', 'please try again');
} else {
Helper.toast('Error', 'just now', jqXHR.responseJSON.meta
.message);
}
resolve({
type: 'error'
});
}
})
})
},
}
const Filter = {
activate: function() {
Filter.event();
},
event: function() {},
triggerFilterCompany: function() {
DTable.reload();
},
}
async function convertImgHtmlToFile(imgHtml, imgWidth, imgHeight, mimeType, fileName) {
return new Promise((resolve, reject) => {
try {
let canvas = document.createElement("canvas")
// Draw image to canvas.
canvas.width = imgWidth
canvas.height = imgHeight
let ctx = canvas.getContext('2d')
ctx.drawImage(imgHtml, 0, 0)
// Convert canvas to ImageState.
let imageData = ctx.getImageData(0, 0, imgWidth, imgHeight)
// console.log(imageState.data.byteLength + ' bytes.')
// Convert canvas to Blob
canvas.toBlob((blob) => {
let newReader = new FileReader();
newReader.addEventListener('loadend', () => {
// Convert canvas to ArrayBuffer
let arrayBuffer = newReader.result
// console.log(arrayBuffer.byteLength + ' bytes.')
// Convert ArrayBuffer to Blob
// let blob = new Blob([arrayBuffer], {type: mimeType})
// Dispay Blob content in an Image.
// console.log(URL.createObjectURL(blob))
// Generate as file
let newFile = new File([arrayBuffer], fileName, {
type: mimeType,
lastModified: new Date(),
size: arrayBuffer.byteLength,
})
resolve(newFile)
});
newReader.readAsArrayBuffer(blob);
}, mimeType);
} catch (e) {
reject(e.message)
}
});
}
// Compress image: clogo
const JimpWorkerAdd = {
worker_clogo: null,
activate: function(x) {
let linkWorker = State.file_jimp_worker
this.setWorker(linkWorker, x, function(res) {
if (res.stts) {
let pureDataURL = res.data.replace(/^data:image\/(png|jpg|jpeg);base64,/, '')
let fileSize = window.atob(pureDataURL).length // in Byte
// (fileSize/1000) + ' Kb'
$('#add-group_' + x + '_spinner').addClass('d-none');
$('#add-' + x + '-status').html('Compressed')
$('#add-' + x + '-filesize').html('<samp>(' + fileSize / 1000 + ' Kb)</samp>')
$('#add-' + x + '-img').attr('src', res.data)
$('#add-' + x + '-img').removeClass('d-none');
$('#add-' + x + '-base64').val(res.data)
} else {
console.error(res.data)
}
$('.page-loader-wrapper').fadeOut()
});
},
runWorker: function(dataURL, x) {
$('#add-group_' + x + '_spinner').removeClass('d-none');
$('#add-' + x + '-img').addClass('d-none');
if (x == 'clogo') {
this.worker_clogo.postMessage(dataURL)
}
},
setWorker: function(urlFileJs, x, cbFinish) {
let worker = new Worker(urlFileJs);
worker.onmessage = function(e) {
// e = {status:(true,false), data:(dataURL)}
// append a new img element using the base 64 image
// let img = document.createElement('img');
// img.setAttribute('src', e.data);
// document.body.appendChild(img);
cbFinish(e.data);
};
if (x == 'clogo') {
this.worker_clogo = worker
}
}
}
const CUploadAdd = {
activate: function(x) {
this.initReader(x)
JimpWorkerAdd.activate(x)
this.event(x)
CRotateImgAdd.activate(x)
},
event: function(x) {
$('#add-' + x + '-choose').on('click', function(e) {
$('#add-' + x + '-file').trigger('click')
})
},
initReader: function(x) {
let reader = new FileReader();
reader = this.setEventFile(reader, x);
$('#add-' + x + '-file').on('change', async function(e) {
try {
if (browserBack()) return false;
let file = e.target.files[0];
let type = file.type.split('/');
if (type[1] == 'jpeg' || type[1] == 'png' || type[1] == 'jpg') {
$('.page-loader-wrapper').fadeIn()
// fix auto rotate when select file
let newImg = await loadImage(file, {
orientation: true
})
let newFile = await convertImgHtmlToFile(newImg.image, newImg
.originalWidth, newImg.originalHeight, file.type, file
.name)
CUploadAdd.readFile(reader, newFile);
$('#add-' + x + '-filesize').html('')
$('#add-' + x + '-status').html('Loading on compressing...')
// $('#add-' + x + '-img').attr('src', '')
$('#add-' + x + '-base64').val('')
} else {
Helper.toast('Validasi', 'just-now', 'Gambar tidak valid');
}
} catch (e) {
console.error(e.message)
}
})
},
setEventFile: function(reader, x) {
reader.onload = function(e) {
let data = e.target.result;
$('#add-' + x + '-img-old').attr('src',
data) // preview, -old mungkin kedepannya bakal diganti jadi -new
// $('#add-'+x+'-img-base64').val(data) // real-data
console.log('Compressing ' + x);
JimpWorkerAdd.runWorker(data, x)
CRotateImgAdd.toggleBtnRotate(x, 'show');
};
reader.onerror = function(err) {
$('.page-loader-wrapper').fadeOut()
$('#' + x).attr('hidden', true)
console.error(err);
};
reader.onabort = function(err) {
console.log(err);
}
return reader;
},
readFile: function(reader, file) {
// reader.readAsArrayBuffer(file);
reader.readAsDataURL(file);
},
}
const CRotateImgAdd = {
activate: function(id) {
this.event(id)
},
event: function(id) {
$('#add-group_rotate_' + id).on('click', '.btnRotateRight', function(e) {
CRotateImgAdd.rotateBase64Image($('#add-' + id + '-base64').val(), 90).then(
function(base64) {
CRotateImgAdd.updateImg(id, base64)
})
})
$('#add-group_rotate_' + id).on('click', '.btnRotateLeft', function(e) {
CRotateImgAdd.rotateBase64Image($('#add-' + id + '-base64').val(), -90).then(
function(base64) {
CRotateImgAdd.updateImg(id, base64)
})
})
},
rotateBase64Image: function(base64data, degrees) {
return new Promise((resolve, reject) => {
try {
let x = 0,
y = 0,
w = 0,
h = 0;
let canvas = document.createElement("canvas");
let image = document.createElement("img"); // new Image();
image.src = base64data; // image.src = 'data:image/jpg;base64,' + base64data;
image.onload = function() {
// current image size for processing rotate
w = image.width;
h = image.height;
let angle = degrees * Math.PI / 180.0; // angle/rads
let ctx = canvas.getContext("2d");
// new image size for after cropped
let c = Math.cos(angle);
let s = Math.sin(angle);
if (s < 0) {
s = -s;
}
if (c < 0) {
c = -c;
}
let rw = h * s + w * c;
let rh = h * c + w * s;
// set canvas size
canvas.width = rw;
canvas.height = rh;
// save the unrotated context of the canvas so we can restore it later
// the alternative is to untranslate & unrotate after drawing
ctx.save();
// draw the rect in the center of the newly sized canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// move to the center of the canvas
// ctx.translate(x+w/2, y+h/2); // ctx.translate(x, h);
// move to the upper left corner when rotating in 90deg increments
ctx.translate(Math.abs(w / 2 * Math.cos(angle) + h / 2 * Math.sin(angle)),
Math.abs(h / 2 * Math.cos(angle) + w / 2 * Math.sin(angle)));
// rotate the canvas to the specified degrees
ctx.rotate(angle); // ctx.rotate(180 * Math.PI / 180);
// move to the center of the canvas (origin)
ctx.translate(-x - w / 2, -y - h / 2);
// since the context is rotated, the image will be rotated also
ctx.drawImage(image, 0, 0, w, h);
// were done with the rotating so restore the unrotated context
ctx.restore();
// convert to base64
resolve(canvas.toDataURL('image/jpeg', 1.0));
};
} catch (err) {
reject(err);
}
});
},
updateImg: function(id, base64) {
// update data
let pureDataURL = base64.replace(/^data:image\/(png|jpg|jpeg);base64,/, '')
let fileSize = window.atob(pureDataURL).length // in Byte
// (fileSize/1000) + ' Kb'
$('#add-' + id + '-status').html('Compressing...')
$('#add-' + id + '-filesize').html('<samp>(' + fileSize / 1000 + ' Kb)</samp>')
$('#add-' + id + '-img').attr('src', base64)
$('#add-' + id + '-base64').val(base64) // real-data
// compress again because base64 from rotate is rather bigger in range 200kb than compress 50kb
if (id == 'clogo') {
JimpWorkerAdd.worker_clogo.postMessage(base64)
}
},
toggleBtnRotate: function(id, hide = 'hidden') {
if (hide == 'show') {
$('#add-group_rotate_' + id).removeClass('d-none')
return true;
}
$('#add-group_rotate_' + id).addClass('d-none')
return true;
},
}
const JimpWorkerUpdt = {
worker_clogo: null,
activate: function(x) {
let linkWorker = State.file_jimp_worker
this.setWorker(linkWorker, x, function(res) {
if (res.stts) {
let pureDataURL = res.data.replace(/^data:image\/(png|jpg|jpeg);base64,/, '')
let fileSize = window.atob(pureDataURL).length // in Byte
// (fileSize/1000) + ' Kb'
$('#updt-group_' + x + '_spinner').addClass('d-none');
$('#updt-' + x + '-status').html('Compressed')
$('#updt-' + x + '-filesize').html('<samp>(' + fileSize / 1000 + ' Kb)</samp>')
$('#updt-' + x + '-img').attr('src', res.data)
$('#updt-' + x + '-img').removeClass('d-none');
$('#updt-' + x + '-base64').val(res.data)
} else {
console.error(res.data)
}
$('.page-loader-wrapper').fadeOut()
});
},
runWorker: function(dataURL, x) {
$('#updt-group_' + x + '_spinner').removeClass('d-none');
$('#updt-' + x + '-img').addClass('d-none');
if (x == 'clogo') {
this.worker_clogo.postMessage(dataURL)
}
},
setWorker: function(urlFileJs, x, cbFinish) {
let worker = new Worker(urlFileJs);
worker.onmessage = function(e) {
// e = {status:(true,false), data:(dataURL)}
// append a new img element using the base 64 image
// let img = document.createElement('img');
// img.setAttribute('src', e.data);
// document.body.appendChild(img);
cbFinish(e.data);
};
if (x == 'clogo') {
this.worker_clogo = worker
}
}
}
const CUploadUpdt = {
activate: function(x) {
this.initReader(x)
JimpWorkerUpdt.activate(x)
this.event(x)
CRotateImgUpdt.activate(x)
},
event: function(x) {
$('#updt-' + x + '-choose').on('click', function(e) {
$('#updt-' + x + '-file').trigger('click')
})
},
initReader: function(x) {
let reader = new FileReader();
reader = this.setEventFile(reader, x);
$('#updt-' + x + '-file').on('change', async function(e) {
try {
if (browserBack()) return false;
let file = e.target.files[0];
let type = file.type.split('/');
if (type[1] == 'jpeg' || type[1] == 'png' || type[1] == 'jpg') {
$('.page-loader-wrapper').fadeIn()
// fix auto rotate when select file
let newImg = await loadImage(file, {
orientation: true
})
let newFile = await convertImgHtmlToFile(newImg.image, newImg
.originalWidth, newImg.originalHeight, file.type, file
.name)
CUploadUpdt.readFile(reader, newFile);
$('#updt-' + x + '-filesize').html('')
$('#updt-' + x + '-status').html('Loading on compressing...')
// $('#updt-' + x + '-img').attr('src', '')
$('#updt-' + x + '-base64').val('')
} else {
Helper.toast('Validasi', 'just-now', 'Gambar tidak valid');
}
} catch (e) {
console.error(e.message)
}
})
},
setEventFile: function(reader, x) {
reader.onload = function(e) {
let data = e.target.result;
$('#updt-' + x + '-img-old').attr('src',
data) // preview, -old mungkin kedepannya bakal diganti jadi -new
// $('#updt-'+x+'-img-base64').val(data) // real-data
console.log('Compressing ' + x);
JimpWorkerUpdt.runWorker(data, x)
CRotateImgUpdt.toggleBtnRotate(x, 'show');
};
reader.onerror = function(err) {
$('.page-loader-wrapper').fadeOut()
$('#' + x).attr('hidden', true)
console.error(err);
};
reader.onabort = function(err) {
console.log(err);
}
return reader;
},
readFile: function(reader, file) {
// reader.readAsArrayBuffer(file);
reader.readAsDataURL(file);
},
}
const CRotateImgUpdt = {
activate: function(id) {
this.event(id)
},
event: function(id) {
$('#updt-group_rotate_' + id).on('click', '.btnRotateRight', function(e) {
CRotateImgUpdt.rotateBase64Image($('#updt-' + id + '-base64').val(), 90).then(
function(base64) {
CRotateImgUpdt.updateImg(id, base64)
})
})
$('#updt-group_rotate_' + id).on('click', '.btnRotateLeft', function(e) {
CRotateImgUpdt.rotateBase64Image($('#updt-' + id + '-base64').val(), -90).then(
function(base64) {
CRotateImgUpdt.updateImg(id, base64)
})
})
},
rotateBase64Image: function(base64data, degrees) {
return new Promise((resolve, reject) => {
try {
let x = 0,
y = 0,
w = 0,
h = 0;
let canvas = document.createElement("canvas");
let image = document.createElement("img"); // new Image();
image.src = base64data; // image.src = 'data:image/jpg;base64,' + base64data;
image.onload = function() {
// current image size for processing rotate
w = image.width;
h = image.height;
let angle = degrees * Math.PI / 180.0; // angle/rads
let ctx = canvas.getContext("2d");
// new image size for after cropped
let c = Math.cos(angle);
let s = Math.sin(angle);
if (s < 0) {
s = -s;
}
if (c < 0) {
c = -c;
}
let rw = h * s + w * c;
let rh = h * c + w * s;
// set canvas size
canvas.width = rw;
canvas.height = rh;
// save the unrotated context of the canvas so we can restore it later
// the alternative is to untranslate & unrotate after drawing
ctx.save();
// draw the rect in the center of the newly sized canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// move to the center of the canvas
// ctx.translate(x+w/2, y+h/2); // ctx.translate(x, h);
// move to the upper left corner when rotating in 90deg increments
ctx.translate(Math.abs(w / 2 * Math.cos(angle) + h / 2 * Math.sin(angle)),
Math.abs(h / 2 * Math.cos(angle) + w / 2 * Math.sin(angle)));
// rotate the canvas to the specified degrees
ctx.rotate(angle); // ctx.rotate(180 * Math.PI / 180);
// move to the center of the canvas (origin)
ctx.translate(-x - w / 2, -y - h / 2);
// since the context is rotated, the image will be rotated also
ctx.drawImage(image, 0, 0, w, h);
// were done with the rotating so restore the unrotated context
ctx.restore();
// convert to base64
resolve(canvas.toDataURL('image/jpeg', 1.0));
};
} catch (err) {
reject(err);
}
});
},
updateImg: function(id, base64) {
// update data
let pureDataURL = base64.replace(/^data:image\/(png|jpg|jpeg);base64,/, '')
let fileSize = window.atob(pureDataURL).length // in Byte
// (fileSize/1000) + ' Kb'
$('#updt-' + id + '-status').html('Compressing...')
$('#updt-' + id + '-filesize').html('<samp>(' + fileSize / 1000 + ' Kb)</samp>')
$('#updt-' + id + '-img').attr('src', base64)
$('#updt-' + id + '-base64').val(base64) // real-data
// compress again because base64 from rotate is rather bigger in range 200kb than compress 50kb
if (id == 'clogo') {
JimpWorkerUpdt.worker_clogo.postMessage(base64)
}
},
toggleBtnRotate: function(id, hide = 'hidden') {
if (hide == 'show') {
$('#updt-group_rotate_' + id).removeClass('d-none')
return true;
}
$('#updt-group_rotate_' + id).addClass('d-none')
return true;
},
}
Wrapper.activate();
</script>
@endsection