initial commit
This commit is contained in:
@@ -0,0 +1,604 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<style>
|
||||
.block-wrapper {
|
||||
margin-top: 10px;
|
||||
border: 1px solid #ddd;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
/* Responsive Video Container */
|
||||
.video-wrapper {
|
||||
position: relative;
|
||||
padding-bottom: 56.25%;
|
||||
/* 16:9 aspect ratio */
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.video-wrapper iframe {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'WHERE ELSE : Add Article',
|
||||
'pageName' => 'Add',
|
||||
'pageParent' => 'Article Management',
|
||||
'pageParentLink' => url('where-else/article'),
|
||||
])
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
|
||||
|
||||
<form id="frmAdd" class="form d-flex flex-column flex-lg-row"
|
||||
action="{{ url('where-else/insert-article') }}" method="post" enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
<div class="d-flex flex-column gap-7 gap-lg-10 w-100 w-lg-300px mb-7 me-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
<div class="card-body text-center pt-0">
|
||||
|
||||
<style>
|
||||
.image-input-placeholder {
|
||||
background-image: url('{{ url('assets/media/svg/files/blank-image.svg') }}');
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .image-input-placeholder {
|
||||
background-image: url('../media/svg/files/blank-image-dark.svg');
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="image-input image-input-empty image-input-outline image-input-placeholder mb-3"
|
||||
data-kt-image-input="true">
|
||||
|
||||
<div class="image-input-wrapper w-150px h-150px"></div>
|
||||
|
||||
<label
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="change" data-bs-toggle="tooltip"
|
||||
title="Change avatar">
|
||||
|
||||
<i class="bi bi-pencil-fill fs-7"></i>
|
||||
|
||||
<input type="file" name="avatar" id="avatar"
|
||||
accept=".png, .jpg, .jpeg" />
|
||||
<input type="hidden" name="avatar_remove" />
|
||||
|
||||
</label>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="cancel" data-bs-toggle="tooltip"
|
||||
title="Cancel avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="remove" data-bs-toggle="tooltip"
|
||||
title="Remove avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="text-muted fs-7">Set the profile picture. Only *.png, *.jpg and *.jpeg
|
||||
image
|
||||
files are accepted</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{-- Active --}}
|
||||
<div class="card-header" style="border: unset;">
|
||||
<div class="required card-title">
|
||||
<h2>Active</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<label class="form-check form-switch form-check-custom form-check-solid">
|
||||
<input class="form-check-input" disabled readonly name="active" type="checkbox"
|
||||
value="1" checked />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Sub Categories</label>
|
||||
<div class="d-flex align-items-center mt-3">
|
||||
@foreach ($subCategoriesView as $item)
|
||||
<label
|
||||
class="form-check form-check-custom form-check-inline form-check-solid me-5 {{ $errors->has('sub_categories') ? 'is-invalid' : '' }}">
|
||||
<input class="form-check-input" name="sub_categories[]"
|
||||
id="sub_categories" type="checkbox" value="{{ $item->id }}"
|
||||
{{ in_array($item->id, old('sub_categories', [])) ? 'checked' : '' }}>
|
||||
<span class="fw-semibold ps-2 fs-6">
|
||||
{{ $item->name . '(' . $item->name_en . ')' }}
|
||||
</span>
|
||||
</label>
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Date</label>
|
||||
<div class="position-relative d-flex align-items-center">
|
||||
<span class="svg-icon svg-icon-2 position-absolute mx-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21 22H3C2.4 22 2 21.6 2 21V5C2 4.4 2.4 4 3 4H21C21.6 4 22 4.4 22 5V21C22 21.6 21.6 22 21 22Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M6 6C5.4 6 5 5.6 5 5V3C5 2.4 5.4 2 6 2C6.6 2 7 2.4 7 3V5C7 5.6 6.6 6 6 6ZM11 5V3C11 2.4 10.6 2 10 2C9.4 2 9 2.4 9 3V5C9 5.6 9.4 6 10 6C10.6 6 11 5.6 11 5ZM15 5V3C15 2.4 14.6 2 14 2C13.4 2 13 2.4 13 3V5C13 5.6 13.4 6 14 6C14.6 6 15 5.6 15 5ZM19 5V3C19 2.4 18.6 2 18 2C17.4 2 17 2.4 17 3V5C17 5.6 17.4 6 18 6C18.6 6 19 5.6 19 5Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M8.8 13.1C9.2 13.1 9.5 13 9.7 12.8C9.9 12.6 10.1 12.3 10.1 11.9C10.1 11.6 10 11.3 9.8 11.1C9.6 10.9 9.3 10.8 9 10.8C8.8 10.8 8.59999 10.8 8.39999 10.9C8.19999 11 8.1 11.1 8 11.2C7.9 11.3 7.8 11.4 7.7 11.6C7.6 11.8 7.5 11.9 7.5 12.1C7.5 12.2 7.4 12.2 7.3 12.3C7.2 12.4 7.09999 12.4 6.89999 12.4C6.69999 12.4 6.6 12.3 6.5 12.2C6.4 12.1 6.3 11.9 6.3 11.7C6.3 11.5 6.4 11.3 6.5 11.1C6.6 10.9 6.8 10.7 7 10.5C7.2 10.3 7.49999 10.1 7.89999 10C8.29999 9.90003 8.60001 9.80003 9.10001 9.80003C9.50001 9.80003 9.80001 9.90003 10.1 10C10.4 10.1 10.7 10.3 10.9 10.4C11.1 10.5 11.3 10.8 11.4 11.1C11.5 11.4 11.6 11.6 11.6 11.9C11.6 12.3 11.5 12.6 11.3 12.9C11.1 13.2 10.9 13.5 10.6 13.7C10.9 13.9 11.2 14.1 11.4 14.3C11.6 14.5 11.8 14.7 11.9 15C12 15.3 12.1 15.5 12.1 15.8C12.1 16.2 12 16.5 11.9 16.8C11.8 17.1 11.5 17.4 11.3 17.7C11.1 18 10.7 18.2 10.3 18.3C9.9 18.4 9.5 18.5 9 18.5C8.5 18.5 8.1 18.4 7.7 18.2C7.3 18 7 17.8 6.8 17.6C6.6 17.4 6.4 17.1 6.3 16.8C6.2 16.5 6.10001 16.3 6.10001 16.1C6.10001 15.9 6.2 15.7 6.3 15.6C6.4 15.5 6.6 15.4 6.8 15.4C6.9 15.4 7.00001 15.4 7.10001 15.5C7.20001 15.6 7.3 15.6 7.3 15.7C7.5 16.2 7.7 16.6 8 16.9C8.3 17.2 8.6 17.3 9 17.3C9.2 17.3 9.5 17.2 9.7 17.1C9.9 17 10.1 16.8 10.3 16.6C10.5 16.4 10.5 16.1 10.5 15.8C10.5 15.3 10.4 15 10.1 14.7C9.80001 14.4 9.50001 14.3 9.10001 14.3C9.00001 14.3 8.9 14.3 8.7 14.3C8.5 14.3 8.39999 14.3 8.39999 14.3C8.19999 14.3 7.99999 14.2 7.89999 14.1C7.79999 14 7.7 13.8 7.7 13.7C7.7 13.5 7.79999 13.4 7.89999 13.2C7.99999 13 8.2 13 8.5 13H8.8V13.1ZM15.3 17.5V12.2C14.3 13 13.6 13.3 13.3 13.3C13.1 13.3 13 13.2 12.9 13.1C12.8 13 12.7 12.8 12.7 12.6C12.7 12.4 12.8 12.3 12.9 12.2C13 12.1 13.2 12 13.6 11.8C14.1 11.6 14.5 11.3 14.7 11.1C14.9 10.9 15.2 10.6 15.5 10.3C15.8 10 15.9 9.80003 15.9 9.70003C15.9 9.60003 16.1 9.60004 16.3 9.60004C16.5 9.60004 16.7 9.70003 16.8 9.80003C16.9 9.90003 17 10.2 17 10.5V17.2C17 18 16.7 18.4 16.2 18.4C16 18.4 15.8 18.3 15.6 18.2C15.4 18.1 15.3 17.8 15.3 17.5Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
<input class="form-control form-control-solid ps-12" placeholder="Date"
|
||||
name="due_date" id="due_date" value="{{ old('due_date') }}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Subject</label>
|
||||
<input type="text" name="name" id="subject" class="form-control mb-2 col-6"
|
||||
value="{{ old('name') }}" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Subject (EN)</label>
|
||||
<input type="text" name="name_en" id="subject_en"
|
||||
class="form-control mb-2 col-6" value="{{ old('name_en') }}" />
|
||||
</div>
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Description</label>
|
||||
<div class="form-control" id="description" name="description"></div>
|
||||
<input type="hidden" id="description_input" name="description" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Description (EN)</label>
|
||||
<div class="form-control" id="description_en" name="description_en"></div>
|
||||
<input type="hidden" id="description_input_en" name="description_en" />
|
||||
|
||||
</div>
|
||||
|
||||
<div hidden class="mb-10">
|
||||
<label class="form-label required">File Video</label>
|
||||
<input class="files-video" type="file" name="file_video[]" multiple
|
||||
accept=".MP4, .MOV">
|
||||
<div class="text-muted fs-7">Allowed Types .MP4, .MOV</div>
|
||||
</div>
|
||||
|
||||
<div hidden class="mb-10">
|
||||
<label class="form-label required">File Image</label>
|
||||
<input class="files-image" type="file" name="file_image[]" multiple
|
||||
accept=".jpg, .bmp, .jpeg, .png">
|
||||
<div class="text-muted fs-7">Allowed Types .jpg, .bmp, .jpeg, .png</div>
|
||||
</div>
|
||||
|
||||
<div hidden class="mb-10">
|
||||
<label class="form-label required">File Sound</label>
|
||||
<input class="files-sound" type="file" name="file_sound[]" multiple
|
||||
accept=".m4a, .mp4, .mp3, .wav">
|
||||
<div class="text-muted fs-7">Allowed Types .m4a, .mp4, .mp3, .wav</div>
|
||||
</div>
|
||||
|
||||
<div hidden class="mb-10">
|
||||
<label class="form-label required">File Documents</label>
|
||||
<input class="files-document" type="file" name="file_document[]" multiple
|
||||
accept=".pdf, .xls, .doc, .docx, .pptx, .csv, .txt">
|
||||
<div class="text-muted fs-7">Allowed Types .pdf, .xls, .doc, .docx, .pptx, .csv,
|
||||
.txt</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('where-else/article') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button id="btn_submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save Changes</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<!-- Include Editor.js core -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest"></script>
|
||||
|
||||
<!-- Include the plugins -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/header"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/list"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/image"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/editorjs-inline-image"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/embed"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/editorjs-break-line"></script>
|
||||
|
||||
<script>
|
||||
// Custom video tool for embedding videos
|
||||
class VideoTool {
|
||||
constructor({
|
||||
data
|
||||
}) {
|
||||
this.data = data || {};
|
||||
}
|
||||
|
||||
// Render input for video URL
|
||||
render() {
|
||||
const wrapper = document.createElement("div");
|
||||
|
||||
const input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.placeholder = "Enter video URL";
|
||||
input.value = this.data.url || "";
|
||||
input.style.width = "100%";
|
||||
|
||||
const video = document.createElement("video");
|
||||
video.controls = true;
|
||||
video.style.width = "100%";
|
||||
video.style.marginTop = "10px";
|
||||
video.src = this.data.url || "";
|
||||
|
||||
input.addEventListener("input", (event) => {
|
||||
const value = event.target.value;
|
||||
this.data.url = value;
|
||||
video.src = value;
|
||||
});
|
||||
|
||||
wrapper.appendChild(input);
|
||||
wrapper.appendChild(video);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
// Save the video URL
|
||||
save(blockContent) {
|
||||
const input = blockContent.querySelector("input");
|
||||
return {
|
||||
url: input.value,
|
||||
};
|
||||
}
|
||||
|
||||
// Editor.js toolbox definition
|
||||
static get toolbox() {
|
||||
return {
|
||||
title: "Video",
|
||||
icon: '<svg width="20" height="20" viewBox="0 0 24 24"><path d="M10 8.64L15.27 12 10 15.36V8.64M10 3.14L21 12 10 20.86V3.14M3 4h4v16H3V4z"></path></svg>',
|
||||
};
|
||||
}
|
||||
}
|
||||
class YoutubeEmbed {
|
||||
/**
|
||||
* Define the toolbox settings for the Editor.js toolbar.
|
||||
*/
|
||||
static get toolbox() {
|
||||
return {
|
||||
title: "YouTube",
|
||||
icon: '<svg width="18" height="18" viewBox="0 0 24 24"><path d="M19.615 3.184c-.403-1.516-1.589-2.693-3.09-3.091-2.719-.727-13.525-.727-16.244 0-1.514.398-2.687 1.57-3.09 3.091-.727 2.719-.727 13.525 0 16.244.403 1.514 1.576 2.693 3.09 3.09 2.719.727 13.525.727 16.244 0 1.516-.397 2.692-1.576 3.09-3.09.727-2.719.727-13.525 0-16.244zm-11.615 13.316v-8l8 4-8 4z"/></svg>',
|
||||
};
|
||||
}
|
||||
|
||||
constructor({
|
||||
data,
|
||||
config,
|
||||
api,
|
||||
readOnly
|
||||
}) {
|
||||
this.data = data || {};
|
||||
this.readOnly = readOnly;
|
||||
this.wrapper = null;
|
||||
this.url = this.data.url || '';
|
||||
this.isEdited = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the input field and YouTube preview.
|
||||
*/
|
||||
render() {
|
||||
this.wrapper = document.createElement('div');
|
||||
this.wrapper.classList.add('block-wrapper');
|
||||
|
||||
const input = document.createElement('input');
|
||||
input.value = this.url;
|
||||
input.placeholder = "Paste YouTube URL here...";
|
||||
input.style.width = '100%';
|
||||
|
||||
this.wrapper.appendChild(input);
|
||||
this._createIframe(this.url);
|
||||
|
||||
input.addEventListener('change', (event) => {
|
||||
this.isEdited = true;
|
||||
this.url = event.target.value;
|
||||
this._createIframe(this.url);
|
||||
});
|
||||
|
||||
return this.wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the iframe for the YouTube video.
|
||||
*/
|
||||
_createIframe(url) {
|
||||
const videoId = this._extractVideoID(url);
|
||||
if (!videoId) {
|
||||
if (this.isEdited) {
|
||||
this.wrapper.querySelector('input').classList.add('invalid');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.wrapper.innerHTML = ''; // Clear the wrapper
|
||||
|
||||
const plyrContainer = document.createElement('div');
|
||||
plyrContainer.classList.add('video-wrapper');
|
||||
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.src = `https://www.youtube.com/embed/${videoId}`;
|
||||
iframe.allowFullscreen = true;
|
||||
|
||||
plyrContainer.appendChild(iframe);
|
||||
this.wrapper.appendChild(plyrContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the YouTube video ID from the URL.
|
||||
*/
|
||||
_extractVideoID(url) {
|
||||
const regex = /(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/)([^&?/]+)/;
|
||||
const match = url.match(regex);
|
||||
return match ? match[1] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the saved data for this block.
|
||||
*/
|
||||
save(blockContent) {
|
||||
return {
|
||||
url: this.url,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the core that this tool supports read-only mode.
|
||||
*/
|
||||
static get isReadOnlySupported() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
||||
const baseUrlUpload = "{{ url('where-else/article-upload-image') }}";
|
||||
const tools = {
|
||||
header: {
|
||||
class: Header,
|
||||
inlineToolbar: ['link', 'bold', 'italic'],
|
||||
config: {
|
||||
placeholder: 'Enter a header',
|
||||
levels: [2, 3, 4], // Set header levels
|
||||
defaultLevel: 3,
|
||||
},
|
||||
},
|
||||
breakLine: {
|
||||
class: BreakLine,
|
||||
inlineToolbar: true,
|
||||
shortcut: 'CMD+SHIFT+ENTER',
|
||||
},
|
||||
youtube: YoutubeEmbed,
|
||||
embed: {
|
||||
class: Embed,
|
||||
inlineToolbar: true,
|
||||
config: {
|
||||
services: {
|
||||
youtube: true,
|
||||
vimeo: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
video: {
|
||||
class: VideoTool,
|
||||
inlineToolbar: true,
|
||||
},
|
||||
image: {
|
||||
class: ImageTool,
|
||||
config: {
|
||||
endpoints: {
|
||||
byFile: baseUrlUpload,
|
||||
byUrl: baseUrlUpload,
|
||||
},
|
||||
field: 'image',
|
||||
types: 'image/*',
|
||||
inlineToolbar: true,
|
||||
additionalRequestHeaders: {
|
||||
'X-CSRF-TOKEN': csrfToken, // Include CSRF token here
|
||||
},
|
||||
},
|
||||
},
|
||||
inlineImage: {
|
||||
class: InlineImage,
|
||||
inlineToolbar: true,
|
||||
config: {
|
||||
embed: {
|
||||
display: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
const editorDescription = new EditorJS({
|
||||
holder: 'description',
|
||||
tools: tools
|
||||
});
|
||||
const editorDescriptionEn = new EditorJS({
|
||||
holder: 'description_en',
|
||||
tools: tools,
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
$('#due_date').flatpickr({
|
||||
enableTime: false,
|
||||
dateFormat: 'd-m-Y',
|
||||
defaultDate: null, // Do not preselect any date
|
||||
onReady: function(selectedDates, dateStr, instance) {
|
||||
// Highlight today's date with a custom CSS class
|
||||
const today = instance.todayDateElem;
|
||||
today.classList.add('flatpickr-today-highlight'); // Add a custom class to today
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('click', '#btn_submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// avatar
|
||||
const avatar = $('#avatar').val();
|
||||
if (avatar == '') {
|
||||
alertFail('Notice', "Avatar is required");
|
||||
return;
|
||||
}
|
||||
|
||||
// categories
|
||||
const subCate = $('#sub_categories');
|
||||
const anySelected = Array.from(subCate).some(checkbox => checkbox.checked);
|
||||
if (!anySelected) {
|
||||
alertFail('Notice', "Sub Categories is required");
|
||||
return;
|
||||
}
|
||||
|
||||
// date
|
||||
const dueDate = $('#due_date').val();
|
||||
if (dueDate == '') {
|
||||
alertFail('Notice', "Date is required");
|
||||
return;
|
||||
}
|
||||
|
||||
// Subject
|
||||
const subject = $('#subject').val();
|
||||
if (subject == '') {
|
||||
alertFail('Notice', "Subject is required");
|
||||
return;
|
||||
}
|
||||
// Subject En
|
||||
const subjectEn = $('#subject_en').val();
|
||||
if (subjectEn == '') {
|
||||
alertFail('Notice', "Subject en is required");
|
||||
return;
|
||||
}
|
||||
|
||||
Promise.all([editorDescription.save(), editorDescriptionEn.save()])
|
||||
.then(([descriptionData, descriptionEnData]) => {
|
||||
|
||||
if (descriptionData?.blocks?.length <= 0) {
|
||||
alertFail('Notice', "Description is required");
|
||||
return;
|
||||
}
|
||||
if (descriptionEnData?.blocks?.length <= 0) {
|
||||
alertFail('Notice', "Description en is required");
|
||||
return;
|
||||
}
|
||||
|
||||
alertLoading("Loading...");
|
||||
|
||||
// Store the JSON output in the hidden input fields
|
||||
$('#description_input').val(JSON.stringify(descriptionData));
|
||||
$('#description_input_en').val(JSON.stringify(descriptionEnData));
|
||||
|
||||
// Submit the form after saving the data
|
||||
$('#frmAdd').submit();
|
||||
})
|
||||
.catch((error) => {
|
||||
hideLoading();
|
||||
console.error('Error saving editor content:', error);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,594 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<style>
|
||||
.video-responsive {
|
||||
position: relative;
|
||||
padding-bottom: 56.25%;
|
||||
/* Aspect ratio 16:9 */
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.video-responsive video {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.block-wrapper {
|
||||
margin-top: 10px;
|
||||
border: 1px solid #ddd;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
/* Responsive Video Container */
|
||||
.video-wrapper {
|
||||
position: relative;
|
||||
padding-bottom: 56.25%;
|
||||
/* 16:9 aspect ratio */
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.video-wrapper iframe {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'WHERE ELSE : Edit Article',
|
||||
'pageName' => 'Edit',
|
||||
'pageParent' => 'Article Management',
|
||||
'pageParentLink' => url('where-else/article'),
|
||||
])
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
|
||||
<form id="frmUpdate" class="form d-flex flex-column flex-lg-row"
|
||||
action="{{ url('where-else/update-article') }}" method="post" enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="id" value="{{ $itemView->id }}">
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
{{-- Left --}}
|
||||
<div class="d-flex flex-column gap-7 gap-lg-10 w-100 w-lg-300px mb-7 me-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
<div class="card-body text-center pt-0">
|
||||
|
||||
<style>
|
||||
.image-input-placeholder {
|
||||
background-image: url('{{ url('assets/media/svg/files/blank-image.svg') }}');
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .image-input-placeholder {
|
||||
background-image: url('../media/svg/files/blank-image-dark.svg');
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="image-input image-input-empty image-input-outline image-input-placeholder mb-3"
|
||||
data-kt-image-input="true">
|
||||
|
||||
|
||||
@if ($itemView->image_url && $itemView->image_name)
|
||||
<div class="image-input-wrapper w-150px h-150px"
|
||||
style="background-image: url('{{ $itemView->image_url . '/thumbnail/' . $itemView->image_name }}')">
|
||||
</div>
|
||||
@else
|
||||
<div class="image-input-wrapper w-150px h-150px"></div>
|
||||
@endif
|
||||
|
||||
<label
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="change" data-bs-toggle="tooltip"
|
||||
title="Change avatar">
|
||||
|
||||
<i class="bi bi-pencil-fill fs-7"></i>
|
||||
|
||||
<input type="file" name="avatar" accept=".png, .jpg, .jpeg" />
|
||||
<input type="hidden" name="avatar_remove" />
|
||||
|
||||
</label>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="cancel" data-bs-toggle="tooltip"
|
||||
title="Cancel avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="remove" data-bs-toggle="tooltip"
|
||||
title="Remove avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="text-muted fs-7">Set the profile picture. Only *.png, *.jpg and *.jpeg
|
||||
image
|
||||
files are accepted</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-header" style="border: unset;">
|
||||
<!--begin::Card title-->
|
||||
<div class="required card-title">
|
||||
<h2>Active</h2>
|
||||
</div>
|
||||
<!--end::Card title-->
|
||||
</div>
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<label class="form-check form-switch form-check-custom form-check-solid">
|
||||
<input class="form-check-input" name="active" type="checkbox" value="1"
|
||||
{{ $itemView->active == 1 ? 'checked' : '' }} />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{{-- Right --}}
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Sub Categories</label>
|
||||
<div class="d-flex align-items-center mt-3">
|
||||
@foreach ($subCategoriesView as $item)
|
||||
<label
|
||||
class="form-check form-check-custom form-check-inline form-check-solid me-5 is-invalid">
|
||||
<input class="form-check-input" name="sub_categories[]" type="checkbox"
|
||||
value="{{ $item->id }}"
|
||||
@if (in_array($item->id, explode(',', $itemView->sub_category_ids))) checked @endif>
|
||||
<span class="fw-semibold ps-2 fs-6">
|
||||
{{ $item->name . '(' . $item->name_en . ')' }}
|
||||
</span>
|
||||
</label>
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<div class="position-relative d-flex align-items-center">
|
||||
<span class="svg-icon svg-icon-2 position-absolute mx-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21 22H3C2.4 22 2 21.6 2 21V5C2 4.4 2.4 4 3 4H21C21.6 4 22 4.4 22 5V21C22 21.6 21.6 22 21 22Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M6 6C5.4 6 5 5.6 5 5V3C5 2.4 5.4 2 6 2C6.6 2 7 2.4 7 3V5C7 5.6 6.6 6 6 6ZM11 5V3C11 2.4 10.6 2 10 2C9.4 2 9 2.4 9 3V5C9 5.6 9.4 6 10 6C10.6 6 11 5.6 11 5ZM15 5V3C15 2.4 14.6 2 14 2C13.4 2 13 2.4 13 3V5C13 5.6 13.4 6 14 6C14.6 6 15 5.6 15 5ZM19 5V3C19 2.4 18.6 2 18 2C17.4 2 17 2.4 17 3V5C17 5.6 17.4 6 18 6C18.6 6 19 5.6 19 5Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M8.8 13.1C9.2 13.1 9.5 13 9.7 12.8C9.9 12.6 10.1 12.3 10.1 11.9C10.1 11.6 10 11.3 9.8 11.1C9.6 10.9 9.3 10.8 9 10.8C8.8 10.8 8.59999 10.8 8.39999 10.9C8.19999 11 8.1 11.1 8 11.2C7.9 11.3 7.8 11.4 7.7 11.6C7.6 11.8 7.5 11.9 7.5 12.1C7.5 12.2 7.4 12.2 7.3 12.3C7.2 12.4 7.09999 12.4 6.89999 12.4C6.69999 12.4 6.6 12.3 6.5 12.2C6.4 12.1 6.3 11.9 6.3 11.7C6.3 11.5 6.4 11.3 6.5 11.1C6.6 10.9 6.8 10.7 7 10.5C7.2 10.3 7.49999 10.1 7.89999 10C8.29999 9.90003 8.60001 9.80003 9.10001 9.80003C9.50001 9.80003 9.80001 9.90003 10.1 10C10.4 10.1 10.7 10.3 10.9 10.4C11.1 10.5 11.3 10.8 11.4 11.1C11.5 11.4 11.6 11.6 11.6 11.9C11.6 12.3 11.5 12.6 11.3 12.9C11.1 13.2 10.9 13.5 10.6 13.7C10.9 13.9 11.2 14.1 11.4 14.3C11.6 14.5 11.8 14.7 11.9 15C12 15.3 12.1 15.5 12.1 15.8C12.1 16.2 12 16.5 11.9 16.8C11.8 17.1 11.5 17.4 11.3 17.7C11.1 18 10.7 18.2 10.3 18.3C9.9 18.4 9.5 18.5 9 18.5C8.5 18.5 8.1 18.4 7.7 18.2C7.3 18 7 17.8 6.8 17.6C6.6 17.4 6.4 17.1 6.3 16.8C6.2 16.5 6.10001 16.3 6.10001 16.1C6.10001 15.9 6.2 15.7 6.3 15.6C6.4 15.5 6.6 15.4 6.8 15.4C6.9 15.4 7.00001 15.4 7.10001 15.5C7.20001 15.6 7.3 15.6 7.3 15.7C7.5 16.2 7.7 16.6 8 16.9C8.3 17.2 8.6 17.3 9 17.3C9.2 17.3 9.5 17.2 9.7 17.1C9.9 17 10.1 16.8 10.3 16.6C10.5 16.4 10.5 16.1 10.5 15.8C10.5 15.3 10.4 15 10.1 14.7C9.80001 14.4 9.50001 14.3 9.10001 14.3C9.00001 14.3 8.9 14.3 8.7 14.3C8.5 14.3 8.39999 14.3 8.39999 14.3C8.19999 14.3 7.99999 14.2 7.89999 14.1C7.79999 14 7.7 13.8 7.7 13.7C7.7 13.5 7.79999 13.4 7.89999 13.2C7.99999 13 8.2 13 8.5 13H8.8V13.1ZM15.3 17.5V12.2C14.3 13 13.6 13.3 13.3 13.3C13.1 13.3 13 13.2 12.9 13.1C12.8 13 12.7 12.8 12.7 12.6C12.7 12.4 12.8 12.3 12.9 12.2C13 12.1 13.2 12 13.6 11.8C14.1 11.6 14.5 11.3 14.7 11.1C14.9 10.9 15.2 10.6 15.5 10.3C15.8 10 15.9 9.80003 15.9 9.70003C15.9 9.60003 16.1 9.60004 16.3 9.60004C16.5 9.60004 16.7 9.70003 16.8 9.80003C16.9 9.90003 17 10.2 17 10.5V17.2C17 18 16.7 18.4 16.2 18.4C16 18.4 15.8 18.3 15.6 18.2C15.4 18.1 15.3 17.8 15.3 17.5Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
<input class="form-control form-control-solid ps-12" type="text"
|
||||
id="due_date" name="due_date"
|
||||
value="{{ $itemView->due_date ? date('d-m-Y', strtotime($itemView->due_date)) : '' }}">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Subject</label>
|
||||
<input type="text" name="name" class="form-control mb-2 col-6"
|
||||
value="{{ $itemView->name }}" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Subject (EN)</label>
|
||||
<input type="text" name="name_en" class="form-control mb-2 col-6"
|
||||
value="{{ $itemView->name_en }}" />
|
||||
</div>
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Description</label>
|
||||
<div class="form-control" id="description" name="description"></div>
|
||||
<input type="hidden" id="description_input" name="description" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Description (EN)</label>
|
||||
<div class="form-control" id="description_en" name="description_en"></div>
|
||||
<input type="hidden" id="description_input_en" name="description_en" />
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('where-else/article') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button type="button" id="btn_submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
$('#due_date').flatpickr({
|
||||
enableTime: false,
|
||||
dateFormat: 'd-m-Y',
|
||||
defaultDate: null, // Do not preselect any date
|
||||
onReady: function(selectedDates, dateStr, instance) {
|
||||
// Highlight today's date with a custom CSS class
|
||||
const today = instance.todayDateElem;
|
||||
today.classList.add('flatpickr-today-highlight'); // Add a custom class to today
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$(document).on("click", "#btn_submit", function(e) {
|
||||
e.preventDefault();
|
||||
alertLoading("Loading")
|
||||
const form = $('#frmUpdate');
|
||||
form.submit();
|
||||
})
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<!-- Include Editor.js core -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest"></script>
|
||||
|
||||
<!-- Include the plugins -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/header"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/list"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/image"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/editorjs-inline-image"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/embed"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/editorjs-break-line"></script>
|
||||
|
||||
<script>
|
||||
// Custom video tool for embedding videos
|
||||
class VideoTool {
|
||||
constructor({
|
||||
data
|
||||
}) {
|
||||
this.data = data || {};
|
||||
}
|
||||
|
||||
// Render input for video URL
|
||||
render() {
|
||||
const wrapper = document.createElement("div");
|
||||
|
||||
const input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.placeholder = "Enter video URL";
|
||||
input.value = this.data.url || "";
|
||||
input.style.width = "100%";
|
||||
|
||||
const video = document.createElement("video");
|
||||
video.controls = true;
|
||||
video.style.width = "100%";
|
||||
video.style.marginTop = "10px";
|
||||
video.src = this.data.url || "";
|
||||
|
||||
input.addEventListener("input", (event) => {
|
||||
const value = event.target.value;
|
||||
this.data.url = value;
|
||||
video.src = value;
|
||||
});
|
||||
|
||||
wrapper.appendChild(input);
|
||||
wrapper.appendChild(video);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
// Save the video URL
|
||||
save(blockContent) {
|
||||
const input = blockContent.querySelector("input");
|
||||
return {
|
||||
url: input.value,
|
||||
};
|
||||
}
|
||||
|
||||
// Editor.js toolbox definition
|
||||
static get toolbox() {
|
||||
return {
|
||||
title: "Video",
|
||||
icon: '<svg width="20" height="20" viewBox="0 0 24 24"><path d="M10 8.64L15.27 12 10 15.36V8.64M10 3.14L21 12 10 20.86V3.14M3 4h4v16H3V4z"></path></svg>',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class YoutubeEmbed {
|
||||
/**
|
||||
* Define the toolbox settings for the Editor.js toolbar.
|
||||
*/
|
||||
static get toolbox() {
|
||||
return {
|
||||
title: "YouTube",
|
||||
icon: '<svg width="18" height="18" viewBox="0 0 24 24"><path d="M19.615 3.184c-.403-1.516-1.589-2.693-3.09-3.091-2.719-.727-13.525-.727-16.244 0-1.514.398-2.687 1.57-3.09 3.091-.727 2.719-.727 13.525 0 16.244.403 1.514 1.576 2.693 3.09 3.09 2.719.727 13.525.727 16.244 0 1.516-.397 2.692-1.576 3.09-3.09.727-2.719.727-13.525 0-16.244zm-11.615 13.316v-8l8 4-8 4z"/></svg>',
|
||||
};
|
||||
}
|
||||
|
||||
constructor({
|
||||
data,
|
||||
config,
|
||||
api,
|
||||
readOnly
|
||||
}) {
|
||||
this.data = data || {};
|
||||
this.readOnly = readOnly;
|
||||
this.wrapper = null;
|
||||
this.url = this.data.url || '';
|
||||
this.isEdited = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the input field and YouTube preview.
|
||||
*/
|
||||
render() {
|
||||
this.wrapper = document.createElement('div');
|
||||
this.wrapper.classList.add('block-wrapper');
|
||||
|
||||
const input = document.createElement('input');
|
||||
input.value = this.url;
|
||||
input.placeholder = "Paste YouTube URL here...";
|
||||
input.style.width = '100%';
|
||||
|
||||
this.wrapper.appendChild(input);
|
||||
this._createIframe(this.url);
|
||||
|
||||
input.addEventListener('change', (event) => {
|
||||
this.isEdited = true;
|
||||
this.url = event.target.value;
|
||||
this._createIframe(this.url);
|
||||
});
|
||||
|
||||
return this.wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the iframe for the YouTube video.
|
||||
*/
|
||||
_createIframe(url) {
|
||||
const videoId = this._extractVideoID(url);
|
||||
if (!videoId) {
|
||||
if (this.isEdited) {
|
||||
this.wrapper.querySelector('input').classList.add('invalid');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.wrapper.innerHTML = ''; // Clear the wrapper
|
||||
|
||||
const plyrContainer = document.createElement('div');
|
||||
plyrContainer.classList.add('video-wrapper');
|
||||
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.src = `https://www.youtube.com/embed/${videoId}`;
|
||||
iframe.allowFullscreen = true;
|
||||
|
||||
plyrContainer.appendChild(iframe);
|
||||
this.wrapper.appendChild(plyrContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the YouTube video ID from the URL.
|
||||
*/
|
||||
_extractVideoID(url) {
|
||||
const regex = /(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/)([^&?/]+)/;
|
||||
const match = url.match(regex);
|
||||
return match ? match[1] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the saved data for this block.
|
||||
*/
|
||||
save(blockContent) {
|
||||
return {
|
||||
url: this.url,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the core that this tool supports read-only mode.
|
||||
*/
|
||||
static get isReadOnlySupported() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
||||
const baseUrlUpload = "{{ url('where-else/article-upload-image') }}";
|
||||
const tools = {
|
||||
header: {
|
||||
class: Header,
|
||||
inlineToolbar: ['link', 'bold', 'italic'],
|
||||
config: {
|
||||
placeholder: 'Enter a header',
|
||||
levels: [2, 3, 4], // Set header levels
|
||||
defaultLevel: 3,
|
||||
},
|
||||
},
|
||||
breakLine: {
|
||||
class: BreakLine,
|
||||
inlineToolbar: true,
|
||||
shortcut: 'CMD+SHIFT+ENTER',
|
||||
},
|
||||
youtube: YoutubeEmbed,
|
||||
embed: {
|
||||
class: Embed,
|
||||
inlineToolbar: true,
|
||||
config: {
|
||||
services: {
|
||||
youtube: true,
|
||||
vimeo: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
video: {
|
||||
class: VideoTool,
|
||||
inlineToolbar: true,
|
||||
},
|
||||
image: {
|
||||
class: ImageTool,
|
||||
config: {
|
||||
endpoints: {
|
||||
byFile: baseUrlUpload,
|
||||
byUrl: baseUrlUpload,
|
||||
},
|
||||
field: 'image',
|
||||
types: 'image/*',
|
||||
inlineToolbar: true,
|
||||
additionalRequestHeaders: {
|
||||
'X-CSRF-TOKEN': csrfToken, // Include CSRF token here
|
||||
},
|
||||
},
|
||||
},
|
||||
inlineImage: {
|
||||
class: InlineImage,
|
||||
inlineToolbar: true,
|
||||
config: {
|
||||
embed: {
|
||||
display: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const descriptionData = {!! json_encode($itemView->description) !!};
|
||||
const editorDescription = new EditorJS({
|
||||
holder: 'description',
|
||||
tools: tools,
|
||||
data: descriptionData != "" ? JSON.parse(descriptionData) : {},
|
||||
onChange: () => {
|
||||
saveData(editorDescription, 'description_input')
|
||||
}
|
||||
});
|
||||
|
||||
const descriptionDataEn = {!! json_encode($itemView->description_en) !!};
|
||||
const editorDescriptionEn = new EditorJS({
|
||||
holder: 'description_en',
|
||||
tools: tools,
|
||||
data: descriptionDataEn !== "" ? JSON.parse(descriptionDataEn) : {},
|
||||
onChange: () => {
|
||||
saveData(editorDescriptionEn, 'description_input_en');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Function to save data to hidden inputs
|
||||
function saveData(editor, inputId) {
|
||||
editor.save().then((outputData) => {
|
||||
document.getElementById(inputId).value = JSON.stringify(outputData);
|
||||
}).catch((error) => {
|
||||
console.error('Saving failed: ', error);
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '#btn_submit', function(e) {
|
||||
e.preventDefault(); // Prevent default form submission
|
||||
|
||||
alertLoading("Loading..."); // Show loading alert (your custom function)
|
||||
|
||||
// Save both editor contents
|
||||
Promise.all([editorDescription.save(), editorDescriptionEn.save()])
|
||||
.then(([descriptionData, descriptionEnData]) => {
|
||||
// Store the JSON output in the hidden input fields
|
||||
$('#description_input').val(JSON.stringify(descriptionData));
|
||||
$('#description_input_en').val(JSON.stringify(descriptionEnData));
|
||||
|
||||
// Submit the form after saving the data
|
||||
$('#frmUpdate').submit();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error saving editor content:', error);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,411 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.breadcrumbList', [
|
||||
'title' => 'WHERE ELSE : Article Management',
|
||||
'pageName' => 'Article Management',
|
||||
])
|
||||
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<!--begin::Content container-->
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
<!--begin::Card-->
|
||||
<div class="card">
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<!--begin::Card header-->
|
||||
<div class="card-header border-0 pt-6">
|
||||
<!--begin::Card title-->
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
</div>
|
||||
|
||||
|
||||
@if (Auth::user()->role != 2)
|
||||
<div class="card-toolbar">
|
||||
<div class="d-flex justify-content-end" data-kt-customer-table-toolbar="base">
|
||||
<a href="{{ url('where-else/add-article') }}" class="btn btn-primary">Add
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card-header border-0 pt-5">
|
||||
|
||||
<div class="card-title">
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
<span class="svg-icon svg-icon-1 position-absolute ms-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<rect opacity="0.5" x="17.0365" y="15.1223" width="8.15546" height="2"
|
||||
rx="1" transform="rotate(45 17.0365 15.1223)" fill="currentColor">
|
||||
</rect>
|
||||
<path
|
||||
d="M11 19C6.55556 19 3 15.4444 3 11C3 6.55556 6.55556 3 11 3C15.4444 3 19 6.55556 19 11C19 15.4444 15.4444 19 11 19ZM11 5C7.53333 5 5 7.53333 5 11C5 14.4667 7.53333 17 11 17C14.4667 17 17 14.4667 17 11C17 7.53333 14.4667 5 11 5Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<input type="text" table-filter="search"
|
||||
class="form-control form-control-solid w-250px ps-15" placeholder="Search" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-toolbar flex-row-fluid justify-content-end gap-5">
|
||||
|
||||
<div class="w-100 mw-150px">
|
||||
<div class="position-relative d-flex align-items-center">
|
||||
<span class="svg-icon svg-icon-2 position-absolute mx-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21 22H3C2.4 22 2 21.6 2 21V5C2 4.4 2.4 4 3 4H21C21.6 4 22 4.4 22 5V21C22 21.6 21.6 22 21 22Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M6 6C5.4 6 5 5.6 5 5V3C5 2.4 5.4 2 6 2C6.6 2 7 2.4 7 3V5C7 5.6 6.6 6 6 6ZM11 5V3C11 2.4 10.6 2 10 2C9.4 2 9 2.4 9 3V5C9 5.6 9.4 6 10 6C10.6 6 11 5.6 11 5ZM15 5V3C15 2.4 14.6 2 14 2C13.4 2 13 2.4 13 3V5C13 5.6 13.4 6 14 6C14.6 6 15 5.6 15 5ZM19 5V3C19 2.4 18.6 2 18 2C17.4 2 17 2.4 17 3V5C17 5.6 17.4 6 18 6C18.6 6 19 5.6 19 5Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M8.8 13.1C9.2 13.1 9.5 13 9.7 12.8C9.9 12.6 10.1 12.3 10.1 11.9C10.1 11.6 10 11.3 9.8 11.1C9.6 10.9 9.3 10.8 9 10.8C8.8 10.8 8.59999 10.8 8.39999 10.9C8.19999 11 8.1 11.1 8 11.2C7.9 11.3 7.8 11.4 7.7 11.6C7.6 11.8 7.5 11.9 7.5 12.1C7.5 12.2 7.4 12.2 7.3 12.3C7.2 12.4 7.09999 12.4 6.89999 12.4C6.69999 12.4 6.6 12.3 6.5 12.2C6.4 12.1 6.3 11.9 6.3 11.7C6.3 11.5 6.4 11.3 6.5 11.1C6.6 10.9 6.8 10.7 7 10.5C7.2 10.3 7.49999 10.1 7.89999 10C8.29999 9.90003 8.60001 9.80003 9.10001 9.80003C9.50001 9.80003 9.80001 9.90003 10.1 10C10.4 10.1 10.7 10.3 10.9 10.4C11.1 10.5 11.3 10.8 11.4 11.1C11.5 11.4 11.6 11.6 11.6 11.9C11.6 12.3 11.5 12.6 11.3 12.9C11.1 13.2 10.9 13.5 10.6 13.7C10.9 13.9 11.2 14.1 11.4 14.3C11.6 14.5 11.8 14.7 11.9 15C12 15.3 12.1 15.5 12.1 15.8C12.1 16.2 12 16.5 11.9 16.8C11.8 17.1 11.5 17.4 11.3 17.7C11.1 18 10.7 18.2 10.3 18.3C9.9 18.4 9.5 18.5 9 18.5C8.5 18.5 8.1 18.4 7.7 18.2C7.3 18 7 17.8 6.8 17.6C6.6 17.4 6.4 17.1 6.3 16.8C6.2 16.5 6.10001 16.3 6.10001 16.1C6.10001 15.9 6.2 15.7 6.3 15.6C6.4 15.5 6.6 15.4 6.8 15.4C6.9 15.4 7.00001 15.4 7.10001 15.5C7.20001 15.6 7.3 15.6 7.3 15.7C7.5 16.2 7.7 16.6 8 16.9C8.3 17.2 8.6 17.3 9 17.3C9.2 17.3 9.5 17.2 9.7 17.1C9.9 17 10.1 16.8 10.3 16.6C10.5 16.4 10.5 16.1 10.5 15.8C10.5 15.3 10.4 15 10.1 14.7C9.80001 14.4 9.50001 14.3 9.10001 14.3C9.00001 14.3 8.9 14.3 8.7 14.3C8.5 14.3 8.39999 14.3 8.39999 14.3C8.19999 14.3 7.99999 14.2 7.89999 14.1C7.79999 14 7.7 13.8 7.7 13.7C7.7 13.5 7.79999 13.4 7.89999 13.2C7.99999 13 8.2 13 8.5 13H8.8V13.1ZM15.3 17.5V12.2C14.3 13 13.6 13.3 13.3 13.3C13.1 13.3 13 13.2 12.9 13.1C12.8 13 12.7 12.8 12.7 12.6C12.7 12.4 12.8 12.3 12.9 12.2C13 12.1 13.2 12 13.6 11.8C14.1 11.6 14.5 11.3 14.7 11.1C14.9 10.9 15.2 10.6 15.5 10.3C15.8 10 15.9 9.80003 15.9 9.70003C15.9 9.60003 16.1 9.60004 16.3 9.60004C16.5 9.60004 16.7 9.70003 16.8 9.80003C16.9 9.90003 17 10.2 17 10.5V17.2C17 18 16.7 18.4 16.2 18.4C16 18.4 15.8 18.3 15.6 18.2C15.4 18.1 15.3 17.8 15.3 17.5Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
<input class="form-control form-control-solid ps-12" placeholder="From"
|
||||
id="due_date_from" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="w-100 mw-150px">
|
||||
<div class="position-relative d-flex align-items-center">
|
||||
<span class="svg-icon svg-icon-2 position-absolute mx-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21 22H3C2.4 22 2 21.6 2 21V5C2 4.4 2.4 4 3 4H21C21.6 4 22 4.4 22 5V21C22 21.6 21.6 22 21 22Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M6 6C5.4 6 5 5.6 5 5V3C5 2.4 5.4 2 6 2C6.6 2 7 2.4 7 3V5C7 5.6 6.6 6 6 6ZM11 5V3C11 2.4 10.6 2 10 2C9.4 2 9 2.4 9 3V5C9 5.6 9.4 6 10 6C10.6 6 11 5.6 11 5ZM15 5V3C15 2.4 14.6 2 14 2C13.4 2 13 2.4 13 3V5C13 5.6 13.4 6 14 6C14.6 6 15 5.6 15 5ZM19 5V3C19 2.4 18.6 2 18 2C17.4 2 17 2.4 17 3V5C17 5.6 17.4 6 18 6C18.6 6 19 5.6 19 5Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M8.8 13.1C9.2 13.1 9.5 13 9.7 12.8C9.9 12.6 10.1 12.3 10.1 11.9C10.1 11.6 10 11.3 9.8 11.1C9.6 10.9 9.3 10.8 9 10.8C8.8 10.8 8.59999 10.8 8.39999 10.9C8.19999 11 8.1 11.1 8 11.2C7.9 11.3 7.8 11.4 7.7 11.6C7.6 11.8 7.5 11.9 7.5 12.1C7.5 12.2 7.4 12.2 7.3 12.3C7.2 12.4 7.09999 12.4 6.89999 12.4C6.69999 12.4 6.6 12.3 6.5 12.2C6.4 12.1 6.3 11.9 6.3 11.7C6.3 11.5 6.4 11.3 6.5 11.1C6.6 10.9 6.8 10.7 7 10.5C7.2 10.3 7.49999 10.1 7.89999 10C8.29999 9.90003 8.60001 9.80003 9.10001 9.80003C9.50001 9.80003 9.80001 9.90003 10.1 10C10.4 10.1 10.7 10.3 10.9 10.4C11.1 10.5 11.3 10.8 11.4 11.1C11.5 11.4 11.6 11.6 11.6 11.9C11.6 12.3 11.5 12.6 11.3 12.9C11.1 13.2 10.9 13.5 10.6 13.7C10.9 13.9 11.2 14.1 11.4 14.3C11.6 14.5 11.8 14.7 11.9 15C12 15.3 12.1 15.5 12.1 15.8C12.1 16.2 12 16.5 11.9 16.8C11.8 17.1 11.5 17.4 11.3 17.7C11.1 18 10.7 18.2 10.3 18.3C9.9 18.4 9.5 18.5 9 18.5C8.5 18.5 8.1 18.4 7.7 18.2C7.3 18 7 17.8 6.8 17.6C6.6 17.4 6.4 17.1 6.3 16.8C6.2 16.5 6.10001 16.3 6.10001 16.1C6.10001 15.9 6.2 15.7 6.3 15.6C6.4 15.5 6.6 15.4 6.8 15.4C6.9 15.4 7.00001 15.4 7.10001 15.5C7.20001 15.6 7.3 15.6 7.3 15.7C7.5 16.2 7.7 16.6 8 16.9C8.3 17.2 8.6 17.3 9 17.3C9.2 17.3 9.5 17.2 9.7 17.1C9.9 17 10.1 16.8 10.3 16.6C10.5 16.4 10.5 16.1 10.5 15.8C10.5 15.3 10.4 15 10.1 14.7C9.80001 14.4 9.50001 14.3 9.10001 14.3C9.00001 14.3 8.9 14.3 8.7 14.3C8.5 14.3 8.39999 14.3 8.39999 14.3C8.19999 14.3 7.99999 14.2 7.89999 14.1C7.79999 14 7.7 13.8 7.7 13.7C7.7 13.5 7.79999 13.4 7.89999 13.2C7.99999 13 8.2 13 8.5 13H8.8V13.1ZM15.3 17.5V12.2C14.3 13 13.6 13.3 13.3 13.3C13.1 13.3 13 13.2 12.9 13.1C12.8 13 12.7 12.8 12.7 12.6C12.7 12.4 12.8 12.3 12.9 12.2C13 12.1 13.2 12 13.6 11.8C14.1 11.6 14.5 11.3 14.7 11.1C14.9 10.9 15.2 10.6 15.5 10.3C15.8 10 15.9 9.80003 15.9 9.70003C15.9 9.60003 16.1 9.60004 16.3 9.60004C16.5 9.60004 16.7 9.70003 16.8 9.80003C16.9 9.90003 17 10.2 17 10.5V17.2C17 18 16.7 18.4 16.2 18.4C16 18.4 15.8 18.3 15.6 18.2C15.4 18.1 15.3 17.8 15.3 17.5Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
<input class="form-control form-control-solid ps-12" placeholder="To"
|
||||
id="due_date_to" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="button" id="btn-submit" class="btn btn-primary">
|
||||
Search
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body py-4">
|
||||
<!--begin::Table-->
|
||||
<table class="table align-middle table-row-dashed fs-6 gy-5" id="data-table-category">
|
||||
<!--begin::Table head-->
|
||||
<thead>
|
||||
<!--begin::Table row-->
|
||||
<tr class="text-start text-muted fw-bold fs-7 text-uppercase gs-0">
|
||||
<th class="min-w-125px">Pic</th>
|
||||
<th class="min-w-125px">Date</th>
|
||||
<th class="min-w-125px">Subject</th>
|
||||
<th class="min-w-125px">Subject (EN)</th>
|
||||
<th class="min-w-125px">Created</th>
|
||||
<th class="min-w-125px">Active</th>
|
||||
<th class="text-end min-w-100px">Manage</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="text-gray-600 fw-semibold">
|
||||
|
||||
@foreach ($itemView as $obj)
|
||||
<tr>
|
||||
<td class="d-flex align-items-center">
|
||||
<div class="symbol symbol-100px symbol-2by3 me-4">
|
||||
@if ($obj->image_url && $obj->image_name)
|
||||
<a class="show-image-preview d-block overlay"
|
||||
href="{{ url($obj->image_url . '/original/' . $obj->image_name) }}">
|
||||
<div class="symbol-label"
|
||||
style="background-image: url('{{ url($obj->image_url . '/thumbnail/' . $obj->image_name) }}')">
|
||||
</div>
|
||||
</a>
|
||||
@else
|
||||
<div class="symbol-label"
|
||||
style="background-image: url('{{ url('assets/media/avatars/blank.png') }}')">
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{{ Carbon\Carbon::parse($obj->due_date)->format('d, M Y') }}
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<a href="#" class="text-gray-800 text-hover-primary mb-1">
|
||||
{{ $obj->name }}
|
||||
</a>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<a href="#" class="text-gray-800 text-hover-primary mb-1">
|
||||
{{ $obj->name_en }}
|
||||
</a>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ Carbon\Carbon::parse($obj->created_at)->format('d, M Y') }}
|
||||
</td>
|
||||
|
||||
|
||||
<td>
|
||||
@if ($obj->active == 1)
|
||||
<span class="badge py-3 px-4 fs-7 badge-light-success">Active</span>
|
||||
@else
|
||||
<span class="badge py-3 px-4 fs-7 badge-light-danger">Inactive</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
||||
<td class="min-w-100px text-end">
|
||||
|
||||
{{-- View --}}
|
||||
{{-- <a href="{{ url('view-sub-category/' . $obj->id) }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm me-1">
|
||||
<span class="svg-icon svg-icon-2">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M17.5 11H6.5C4 11 2 9 2 6.5C2 4 4 2 6.5 2H17.5C20 2 22 4 22 6.5C22 9 20 11 17.5 11ZM15 6.5C15 7.9 16.1 9 17.5 9C18.9 9 20 7.9 20 6.5C20 5.1 18.9 4 17.5 4C16.1 4 15 5.1 15 6.5Z"
|
||||
fill="currentColor"></path>
|
||||
<path opacity="0.3"
|
||||
d="M17.5 22H6.5C4 22 2 20 2 17.5C2 15 4 13 6.5 13H17.5C20 13 22 15 22 17.5C22 20 20 22 17.5 22ZM4 17.5C4 18.9 5.1 20 6.5 20C7.9 20 9 18.9 9 17.5C9 16.1 7.9 15 6.5 15C5.1 15 4 16.1 4 17.5Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
</a> --}}
|
||||
|
||||
{{-- Edit --}}
|
||||
<a href="{{ url('where-else/edit-article/' . $obj->id) }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm me-1">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21.4 8.35303L19.241 10.511L13.485 4.755L15.643 2.59595C16.0248 2.21423 16.5426 1.99988 17.0825 1.99988C17.6224 1.99988 18.1402 2.21423 18.522 2.59595L21.4 5.474C21.7817 5.85581 21.9962 6.37355 21.9962 6.91345C21.9962 7.45335 21.7817 7.97122 21.4 8.35303ZM3.68699 21.932L9.88699 19.865L4.13099 14.109L2.06399 20.309C1.98815 20.5354 1.97703 20.7787 2.03189 21.0111C2.08674 21.2436 2.2054 21.4561 2.37449 21.6248C2.54359 21.7934 2.75641 21.9115 2.989 21.9658C3.22158 22.0201 3.4647 22.0084 3.69099 21.932H3.68699Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M5.574 21.3L3.692 21.928C3.46591 22.0032 3.22334 22.0141 2.99144 21.9594C2.75954 21.9046 2.54744 21.7864 2.3789 21.6179C2.21036 21.4495 2.09202 21.2375 2.03711 21.0056C1.9822 20.7737 1.99289 20.5312 2.06799 20.3051L2.696 18.422L5.574 21.3ZM4.13499 14.105L9.891 19.861L19.245 10.507L13.489 4.75098L4.13499 14.105Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{{-- Delete --}}
|
||||
@if ($obj->active == 1 && Auth::user()->role != 2)
|
||||
<a href="#" data-id="{{ $obj->id }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm delete-item">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5 9C5 8.44772 5.44772 8 6 8H18C18.5523 8 19 8.44772 19 9V18C19 19.6569 17.6569 21 16 21H8C6.34315 21 5 19.6569 5 18V9Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M5 5C5 4.44772 5.44772 4 6 4H18C18.5523 4 19 4.44772 19 5V5C19 5.55228 18.5523 6 18 6H6C5.44772 6 5 5.55228 5 5V5Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M9 4C9 3.44772 9.44772 3 10 3H14C14.5523 3 15 3.44772 15 4V4H9V4Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
const baseUrl = "{{ url('where-else/article') }}";
|
||||
var datatable;
|
||||
datatable = $("#data-table-category").DataTable({
|
||||
"info": false,
|
||||
"order": [],
|
||||
"pageLength": 25,
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, 500, 1000],
|
||||
[10, 25, 50, 100, 500, 1000]
|
||||
]
|
||||
});
|
||||
|
||||
// Filter by search
|
||||
const filterSearch = document.querySelector('[table-filter="search"]');
|
||||
filterSearch.addEventListener('keyup', function(e) {
|
||||
datatable.search(e.target.value).draw();
|
||||
});
|
||||
|
||||
// filter by status
|
||||
const filterStatus = document.querySelector('[table-filter="status"]');
|
||||
$(filterStatus).on('change', e => {
|
||||
let value = e.target.value;
|
||||
if (value === 'all') {
|
||||
value = '';
|
||||
}
|
||||
datatable.column(4).search(value).draw();
|
||||
});
|
||||
|
||||
|
||||
// Remove
|
||||
$(document).on('click', '.delete-item', function() {
|
||||
swal.fire({
|
||||
allowOutsideClick: false,
|
||||
text: "Are you sure you would like to Delete?",
|
||||
icon: "warning",
|
||||
buttonsStyling: false,
|
||||
showDenyButton: true,
|
||||
confirmButtonText: "Yes",
|
||||
denyButtonText: 'No',
|
||||
customClass: {
|
||||
confirmButton: "btn btn-primary",
|
||||
denyButton: "btn btn-light-danger"
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
// set up ajax
|
||||
initAjaxSetupToken();
|
||||
|
||||
const ajaxProp = {
|
||||
url: "{{ url('where-else/delete-article') }}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
item_id: $(this).data('id')
|
||||
},
|
||||
};
|
||||
|
||||
$.ajax(ajaxProp).done(function(res) {
|
||||
if (res.status) {
|
||||
const url = "{{ url('where-else/article') }}";
|
||||
alertSuccessWithUrl('Notice', "Delete success", url);
|
||||
hideLoading();
|
||||
} else {
|
||||
alertFail('Notice', res.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
logAjaxError(xhr, status, error);
|
||||
alertFail('Notice', error.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
var today = new Date();
|
||||
var dateFormat = "d-m-Y";
|
||||
|
||||
var dueDateFrom = $("#due_date_from");
|
||||
var dueDateTo = $("#due_date_to");
|
||||
|
||||
const dateFrom = "{{ $fromDateView }}";
|
||||
const dateTo = "{{ $toDateView }}";
|
||||
|
||||
dueDateFrom.flatpickr({
|
||||
showClearButton: true,
|
||||
enableTime: false,
|
||||
dateFormat: dateFormat,
|
||||
maxDate: today,
|
||||
defaultDate: dateFrom,
|
||||
|
||||
});
|
||||
|
||||
dueDateTo.flatpickr({
|
||||
showClearButton: true,
|
||||
enableTime: false,
|
||||
dateFormat: dateFormat,
|
||||
maxDate: today,
|
||||
defaultDate: dateTo,
|
||||
|
||||
});
|
||||
|
||||
const clearDatePicker = () => {
|
||||
dueDateFrom.flatpickr().clear();
|
||||
dueDateTo.flatpickr().clear();
|
||||
|
||||
// Set the date format again after clearing
|
||||
dueDateFrom.flatpickr({
|
||||
dateFormat: dateFormat
|
||||
});
|
||||
dueDateTo.flatpickr({
|
||||
dateFormat: dateFormat
|
||||
});
|
||||
}
|
||||
|
||||
$('#btn-submit').on('click', (e) => {
|
||||
e.preventDefault(); // Prevent the default behavior of the anchor element
|
||||
|
||||
// from
|
||||
const fromDateSelected = $("#due_date_from").val();
|
||||
|
||||
// to
|
||||
const toDateSelected = $("#due_date_to").val();
|
||||
|
||||
if (fromDateSelected && toDateSelected) {
|
||||
var newUrl =
|
||||
`${baseUrl}/${fromDateSelected}/${toDateSelected}`;
|
||||
window.location.href = newUrl;
|
||||
} else {
|
||||
var newUrl = `${baseUrl}/all/all/`;
|
||||
window.location.href = newUrl;
|
||||
}
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,620 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<style>
|
||||
.youtube-preview {
|
||||
margin-top: 10px;
|
||||
width: 100%;
|
||||
max-width: 560px;
|
||||
height: 315px;
|
||||
}
|
||||
|
||||
.block-wrapper {
|
||||
margin-top: 10px;
|
||||
border: 1px solid #ddd;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
/* Responsive Video Container */
|
||||
.video-wrapper {
|
||||
position: relative;
|
||||
padding-bottom: 56.25%;
|
||||
/* 16:9 aspect ratio */
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.video-wrapper iframe {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'CHIANG MAI AND NOWHERE ELSE : Add Article',
|
||||
'pageName' => 'Add',
|
||||
'pageParent' => 'Article Management',
|
||||
'pageParentLink' => url('no-where-else/article'),
|
||||
])
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
|
||||
|
||||
<form id="frmAdd" class="form d-flex flex-column flex-lg-row"
|
||||
action="{{ url('no-where-else/insert-article') }}" method="post" enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
<div class="d-flex flex-column gap-7 gap-lg-10 w-100 w-lg-300px mb-7 me-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
<div class="card-body text-center pt-0">
|
||||
|
||||
<style>
|
||||
.image-input-placeholder {
|
||||
background-image: url('{{ url('assets/media/svg/files/blank-image.svg') }}');
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .image-input-placeholder {
|
||||
background-image: url('../media/svg/files/blank-image-dark.svg');
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="image-input image-input-empty image-input-outline image-input-placeholder mb-3"
|
||||
data-kt-image-input="true">
|
||||
|
||||
<div class="image-input-wrapper w-150px h-150px"></div>
|
||||
|
||||
<label
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="change" data-bs-toggle="tooltip"
|
||||
title="Change avatar">
|
||||
|
||||
<i class="bi bi-pencil-fill fs-7"></i>
|
||||
|
||||
<input type="file" name="avatar" id="avatar"
|
||||
accept=".png, .jpg, .jpeg" />
|
||||
<input type="hidden" name="avatar_remove" />
|
||||
|
||||
</label>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="cancel" data-bs-toggle="tooltip"
|
||||
title="Cancel avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="remove" data-bs-toggle="tooltip"
|
||||
title="Remove avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="text-muted fs-7">Set the profile picture. Only *.png, *.jpg and *.jpeg
|
||||
image
|
||||
files are accepted</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{-- Active --}}
|
||||
<div class="card-header" style="border: unset;">
|
||||
<div class="required card-title">
|
||||
<h2>Active</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<label class="form-check form-switch form-check-custom form-check-solid">
|
||||
<input class="form-check-input" disabled readonly name="active" type="checkbox"
|
||||
value="1" checked />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Sub Categories</label>
|
||||
<div class="d-flex align-items-center mt-3">
|
||||
@foreach ($subCategoriesView as $item)
|
||||
<label
|
||||
class="form-check form-check-custom form-check-inline form-check-solid me-5 {{ $errors->has('sub_categories') ? 'is-invalid' : '' }}">
|
||||
<input class="form-check-input" name="sub_categories[]"
|
||||
id="sub_categories" type="checkbox" value="{{ $item->id }}"
|
||||
{{ in_array($item->id, old('sub_categories', [])) ? 'checked' : '' }}>
|
||||
<span class="fw-semibold ps-2 fs-6">
|
||||
{{ $item->name . '(' . $item->name_en . ')' }}
|
||||
</span>
|
||||
</label>
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Date</label>
|
||||
<div class="position-relative d-flex align-items-center">
|
||||
<span class="svg-icon svg-icon-2 position-absolute mx-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21 22H3C2.4 22 2 21.6 2 21V5C2 4.4 2.4 4 3 4H21C21.6 4 22 4.4 22 5V21C22 21.6 21.6 22 21 22Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M6 6C5.4 6 5 5.6 5 5V3C5 2.4 5.4 2 6 2C6.6 2 7 2.4 7 3V5C7 5.6 6.6 6 6 6ZM11 5V3C11 2.4 10.6 2 10 2C9.4 2 9 2.4 9 3V5C9 5.6 9.4 6 10 6C10.6 6 11 5.6 11 5ZM15 5V3C15 2.4 14.6 2 14 2C13.4 2 13 2.4 13 3V5C13 5.6 13.4 6 14 6C14.6 6 15 5.6 15 5ZM19 5V3C19 2.4 18.6 2 18 2C17.4 2 17 2.4 17 3V5C17 5.6 17.4 6 18 6C18.6 6 19 5.6 19 5Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M8.8 13.1C9.2 13.1 9.5 13 9.7 12.8C9.9 12.6 10.1 12.3 10.1 11.9C10.1 11.6 10 11.3 9.8 11.1C9.6 10.9 9.3 10.8 9 10.8C8.8 10.8 8.59999 10.8 8.39999 10.9C8.19999 11 8.1 11.1 8 11.2C7.9 11.3 7.8 11.4 7.7 11.6C7.6 11.8 7.5 11.9 7.5 12.1C7.5 12.2 7.4 12.2 7.3 12.3C7.2 12.4 7.09999 12.4 6.89999 12.4C6.69999 12.4 6.6 12.3 6.5 12.2C6.4 12.1 6.3 11.9 6.3 11.7C6.3 11.5 6.4 11.3 6.5 11.1C6.6 10.9 6.8 10.7 7 10.5C7.2 10.3 7.49999 10.1 7.89999 10C8.29999 9.90003 8.60001 9.80003 9.10001 9.80003C9.50001 9.80003 9.80001 9.90003 10.1 10C10.4 10.1 10.7 10.3 10.9 10.4C11.1 10.5 11.3 10.8 11.4 11.1C11.5 11.4 11.6 11.6 11.6 11.9C11.6 12.3 11.5 12.6 11.3 12.9C11.1 13.2 10.9 13.5 10.6 13.7C10.9 13.9 11.2 14.1 11.4 14.3C11.6 14.5 11.8 14.7 11.9 15C12 15.3 12.1 15.5 12.1 15.8C12.1 16.2 12 16.5 11.9 16.8C11.8 17.1 11.5 17.4 11.3 17.7C11.1 18 10.7 18.2 10.3 18.3C9.9 18.4 9.5 18.5 9 18.5C8.5 18.5 8.1 18.4 7.7 18.2C7.3 18 7 17.8 6.8 17.6C6.6 17.4 6.4 17.1 6.3 16.8C6.2 16.5 6.10001 16.3 6.10001 16.1C6.10001 15.9 6.2 15.7 6.3 15.6C6.4 15.5 6.6 15.4 6.8 15.4C6.9 15.4 7.00001 15.4 7.10001 15.5C7.20001 15.6 7.3 15.6 7.3 15.7C7.5 16.2 7.7 16.6 8 16.9C8.3 17.2 8.6 17.3 9 17.3C9.2 17.3 9.5 17.2 9.7 17.1C9.9 17 10.1 16.8 10.3 16.6C10.5 16.4 10.5 16.1 10.5 15.8C10.5 15.3 10.4 15 10.1 14.7C9.80001 14.4 9.50001 14.3 9.10001 14.3C9.00001 14.3 8.9 14.3 8.7 14.3C8.5 14.3 8.39999 14.3 8.39999 14.3C8.19999 14.3 7.99999 14.2 7.89999 14.1C7.79999 14 7.7 13.8 7.7 13.7C7.7 13.5 7.79999 13.4 7.89999 13.2C7.99999 13 8.2 13 8.5 13H8.8V13.1ZM15.3 17.5V12.2C14.3 13 13.6 13.3 13.3 13.3C13.1 13.3 13 13.2 12.9 13.1C12.8 13 12.7 12.8 12.7 12.6C12.7 12.4 12.8 12.3 12.9 12.2C13 12.1 13.2 12 13.6 11.8C14.1 11.6 14.5 11.3 14.7 11.1C14.9 10.9 15.2 10.6 15.5 10.3C15.8 10 15.9 9.80003 15.9 9.70003C15.9 9.60003 16.1 9.60004 16.3 9.60004C16.5 9.60004 16.7 9.70003 16.8 9.80003C16.9 9.90003 17 10.2 17 10.5V17.2C17 18 16.7 18.4 16.2 18.4C16 18.4 15.8 18.3 15.6 18.2C15.4 18.1 15.3 17.8 15.3 17.5Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
<input class="form-control form-control-solid ps-12" placeholder="Date"
|
||||
name="due_date" id="due_date" value="{{ old('due_date') }}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Subject</label>
|
||||
<input type="text" name="name" id="subject" class="form-control mb-2 col-6"
|
||||
value="{{ old('name') }}" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Subject (EN)</label>
|
||||
<input type="text" id="subject_en" name="name_en"
|
||||
class="form-control mb-2 col-6" value="{{ old('name_en') }}" />
|
||||
</div>
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Description</label>
|
||||
<div class="form-control" id="description" name="description"></div>
|
||||
<input type="hidden" id="description_input" name="description" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Description (EN)</label>
|
||||
<div class="form-control" id="description_en" name="description_en"></div>
|
||||
<input type="hidden" id="description_input_en" name="description_en" />
|
||||
|
||||
</div>
|
||||
|
||||
<div hidden class="mb-10">
|
||||
<label class="form-label required">File Video</label>
|
||||
<input class="files-video" type="file" name="file_video[]" multiple
|
||||
accept=".MP4, .MOV">
|
||||
<div class="text-muted fs-7">Allowed Types .MP4, .MOV</div>
|
||||
</div>
|
||||
|
||||
<div hidden class="mb-10">
|
||||
<label class="form-label required">File Image</label>
|
||||
<input class="files-image" type="file" name="file_image[]" multiple
|
||||
accept=".jpg, .bmp, .jpeg, .png">
|
||||
<div class="text-muted fs-7">Allowed Types .jpg, .bmp, .jpeg, .png</div>
|
||||
</div>
|
||||
|
||||
<div hidden class="mb-10">
|
||||
<label class="form-label required">File Sound</label>
|
||||
<input class="files-sound" type="file" name="file_sound[]" multiple
|
||||
accept=".m4a, .mp4, .mp3, .wav">
|
||||
<div class="text-muted fs-7">Allowed Types .m4a, .mp4, .mp3, .wav</div>
|
||||
</div>
|
||||
|
||||
<div hidden class="mb-10">
|
||||
<label class="form-label required">File Documents</label>
|
||||
<input class="files-document" type="file" name="file_document[]" multiple
|
||||
accept=".pdf, .xls, .doc, .docx, .pptx, .csv, .txt">
|
||||
<div class="text-muted fs-7">Allowed Types .pdf, .xls, .doc, .docx, .pptx, .csv,
|
||||
.txt</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('no-where-else/article') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button id="btn_submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save Changes</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<!-- Include Editor.js core -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest"></script>
|
||||
|
||||
<!-- Include the plugins -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/header"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/list"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/image"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/editorjs-inline-image"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/embed"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/editorjs-break-line"></script>
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
// Custom video tool for embedding videos
|
||||
class VideoTool {
|
||||
constructor({
|
||||
data
|
||||
}) {
|
||||
this.data = data || {};
|
||||
}
|
||||
|
||||
// Render input for video URL
|
||||
render() {
|
||||
const wrapper = document.createElement("div");
|
||||
|
||||
const input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.placeholder = "Enter video URL";
|
||||
input.value = this.data.url || "";
|
||||
input.style.width = "100%";
|
||||
|
||||
const video = document.createElement("video");
|
||||
video.controls = true;
|
||||
video.style.width = "100%";
|
||||
video.style.marginTop = "10px";
|
||||
video.src = this.data.url || "";
|
||||
|
||||
input.addEventListener("input", (event) => {
|
||||
const value = event.target.value;
|
||||
this.data.url = value;
|
||||
video.src = value;
|
||||
});
|
||||
|
||||
wrapper.appendChild(input);
|
||||
wrapper.appendChild(video);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
// Save the video URL
|
||||
save(blockContent) {
|
||||
const input = blockContent.querySelector("input");
|
||||
return {
|
||||
url: input.value,
|
||||
};
|
||||
}
|
||||
|
||||
// Editor.js toolbox definition
|
||||
static get toolbox() {
|
||||
return {
|
||||
title: "Video",
|
||||
icon: '<svg width="20" height="20" viewBox="0 0 24 24"><path d="M10 8.64L15.27 12 10 15.36V8.64M10 3.14L21 12 10 20.86V3.14M3 4h4v16H3V4z"></path></svg>',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class YoutubeEmbed {
|
||||
/**
|
||||
* Define the toolbox settings for the Editor.js toolbar.
|
||||
*/
|
||||
static get toolbox() {
|
||||
return {
|
||||
title: "YouTube",
|
||||
icon: '<svg width="18" height="18" viewBox="0 0 24 24"><path d="M19.615 3.184c-.403-1.516-1.589-2.693-3.09-3.091-2.719-.727-13.525-.727-16.244 0-1.514.398-2.687 1.57-3.09 3.091-.727 2.719-.727 13.525 0 16.244.403 1.514 1.576 2.693 3.09 3.09 2.719.727 13.525.727 16.244 0 1.516-.397 2.692-1.576 3.09-3.09.727-2.719.727-13.525 0-16.244zm-11.615 13.316v-8l8 4-8 4z"/></svg>',
|
||||
};
|
||||
}
|
||||
|
||||
constructor({
|
||||
data,
|
||||
config,
|
||||
api,
|
||||
readOnly
|
||||
}) {
|
||||
this.data = data || {};
|
||||
this.readOnly = readOnly;
|
||||
this.wrapper = null;
|
||||
this.url = this.data.url || '';
|
||||
this.isEdited = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the input field and YouTube preview.
|
||||
*/
|
||||
render() {
|
||||
this.wrapper = document.createElement('div');
|
||||
this.wrapper.classList.add('block-wrapper');
|
||||
|
||||
const input = document.createElement('input');
|
||||
input.value = this.url;
|
||||
input.placeholder = "Paste YouTube URL here...";
|
||||
input.style.width = '100%';
|
||||
|
||||
this.wrapper.appendChild(input);
|
||||
this._createIframe(this.url);
|
||||
|
||||
input.addEventListener('change', (event) => {
|
||||
this.isEdited = true;
|
||||
this.url = event.target.value;
|
||||
this._createIframe(this.url);
|
||||
});
|
||||
|
||||
return this.wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the iframe for the YouTube video.
|
||||
*/
|
||||
_createIframe(url) {
|
||||
const videoId = this._extractVideoID(url);
|
||||
if (!videoId) {
|
||||
if (this.isEdited) {
|
||||
this.wrapper.querySelector('input').classList.add('invalid');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.wrapper.innerHTML = ''; // Clear the wrapper
|
||||
|
||||
const plyrContainer = document.createElement('div');
|
||||
plyrContainer.classList.add('video-wrapper');
|
||||
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.src = `https://www.youtube.com/embed/${videoId}`;
|
||||
iframe.allowFullscreen = true;
|
||||
|
||||
plyrContainer.appendChild(iframe);
|
||||
this.wrapper.appendChild(plyrContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the YouTube video ID from the URL.
|
||||
*/
|
||||
_extractVideoID(url) {
|
||||
const regex = /(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/)([^&?/]+)/;
|
||||
const match = url.match(regex);
|
||||
return match ? match[1] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the saved data for this block.
|
||||
*/
|
||||
save(blockContent) {
|
||||
return {
|
||||
url: this.url,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the core that this tool supports read-only mode.
|
||||
*/
|
||||
static get isReadOnlySupported() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
||||
const baseUrlUpload = "{{ url('no-where-else/article-upload-image') }}";
|
||||
|
||||
const tools = {
|
||||
header: {
|
||||
class: Header,
|
||||
inlineToolbar: ['link', 'bold', 'italic'],
|
||||
config: {
|
||||
placeholder: 'Enter a header',
|
||||
levels: [2, 3, 4], // Set header levels
|
||||
defaultLevel: 3,
|
||||
},
|
||||
},
|
||||
breakLine: {
|
||||
class: BreakLine,
|
||||
inlineToolbar: true,
|
||||
shortcut: 'CMD+SHIFT+ENTER',
|
||||
},
|
||||
youtube: YoutubeEmbed,
|
||||
embed: {
|
||||
class: Embed,
|
||||
inlineToolbar: true,
|
||||
config: {
|
||||
services: {
|
||||
youtube: true,
|
||||
vimeo: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
video: {
|
||||
class: VideoTool,
|
||||
inlineToolbar: true,
|
||||
},
|
||||
image: {
|
||||
class: ImageTool,
|
||||
config: {
|
||||
endpoints: {
|
||||
byFile: baseUrlUpload,
|
||||
byUrl: baseUrlUpload,
|
||||
},
|
||||
field: 'image',
|
||||
types: 'image/*',
|
||||
inlineToolbar: true,
|
||||
additionalRequestHeaders: {
|
||||
'X-CSRF-TOKEN': csrfToken, // Include CSRF token here
|
||||
},
|
||||
},
|
||||
},
|
||||
inlineImage: {
|
||||
class: InlineImage,
|
||||
inlineToolbar: true,
|
||||
config: {
|
||||
embed: {
|
||||
display: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const editorDescription = new EditorJS({
|
||||
holder: 'description',
|
||||
tools: tools
|
||||
});
|
||||
const editorDescriptionEn = new EditorJS({
|
||||
holder: 'description_en',
|
||||
tools: tools,
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
$('#due_date').flatpickr({
|
||||
enableTime: false,
|
||||
dateFormat: 'd-m-Y',
|
||||
defaultDate: null, // Do not preselect any date
|
||||
onReady: function(selectedDates, dateStr, instance) {
|
||||
// Highlight today's date with a custom CSS class
|
||||
const today = instance.todayDateElem;
|
||||
today.classList.add('flatpickr-today-highlight'); // Add a custom class to today
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('click', '#btn_submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// avatar
|
||||
const avatar = $('#avatar').val();
|
||||
if (avatar == '') {
|
||||
alertFail('Notice', "Avatar is required");
|
||||
return;
|
||||
}
|
||||
|
||||
// categories
|
||||
const subCate = $('#sub_categories');
|
||||
const anySelected = Array.from(subCate).some(checkbox => checkbox.checked);
|
||||
if (!anySelected) {
|
||||
alertFail('Notice', "Sub Categories is required");
|
||||
return;
|
||||
}
|
||||
|
||||
// date
|
||||
const dueDate = $('#due_date').val();
|
||||
if (dueDate == '') {
|
||||
alertFail('Notice', "Date is required");
|
||||
return;
|
||||
}
|
||||
|
||||
// Subject
|
||||
const subject = $('#subject').val();
|
||||
if (subject == '') {
|
||||
alertFail('Notice', "Subject is required");
|
||||
return;
|
||||
}
|
||||
// Subject En
|
||||
const subjectEn = $('#subject_en').val();
|
||||
if (subjectEn == '') {
|
||||
alertFail('Notice', "Subject en is required");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Save both editor contents
|
||||
Promise.all([editorDescription.save(), editorDescriptionEn.save()])
|
||||
.then(([descriptionData, descriptionEnData]) => {
|
||||
|
||||
if (descriptionData?.blocks?.length <= 0) {
|
||||
alertFail('Notice', "Description is required");
|
||||
return;
|
||||
}
|
||||
if (descriptionEnData?.blocks?.length <= 0) {
|
||||
alertFail('Notice', "Description en is required");
|
||||
return;
|
||||
}
|
||||
|
||||
alertLoading("Loading...");
|
||||
|
||||
// Store the JSON output in the hidden input fields
|
||||
$('#description_input').val(JSON.stringify(descriptionData));
|
||||
$('#description_input_en').val(JSON.stringify(descriptionEnData));
|
||||
|
||||
// Submit the form after saving the data
|
||||
$('#frmAdd').submit();
|
||||
})
|
||||
.catch((error) => {
|
||||
hideLoading();
|
||||
console.error('Error saving editor content:', error);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,604 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<style>
|
||||
.video-responsive {
|
||||
position: relative;
|
||||
padding-bottom: 56.25%;
|
||||
/* Aspect ratio 16:9 */
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.video-responsive video {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.block-wrapper {
|
||||
margin-top: 10px;
|
||||
border: 1px solid #ddd;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
/* Responsive Video Container */
|
||||
.video-wrapper {
|
||||
position: relative;
|
||||
padding-bottom: 56.25%;
|
||||
/* 16:9 aspect ratio */
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Responsive Video Container */
|
||||
.video-wrapper {
|
||||
position: relative;
|
||||
padding-bottom: 56.25%;
|
||||
/* 16:9 aspect ratio */
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.video-wrapper iframe {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'CHIANG MAI AND NOWHERE ELSE : Edit Article',
|
||||
'pageName' => 'Edit',
|
||||
'pageParent' => 'Article Management',
|
||||
'pageParentLink' => url('no-where-else/article'),
|
||||
])
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
|
||||
<form id="frmUpdate" class="form d-flex flex-column flex-lg-row"
|
||||
action="{{ url('no-where-else/update-article') }}" method="post" enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="id" value="{{ $itemView->id }}">
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
{{-- Left --}}
|
||||
<div class="d-flex flex-column gap-7 gap-lg-10 w-100 w-lg-300px mb-7 me-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
<div class="card-body text-center pt-0">
|
||||
|
||||
<style>
|
||||
.image-input-placeholder {
|
||||
background-image: url('{{ url('assets/media/svg/files/blank-image.svg') }}');
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .image-input-placeholder {
|
||||
background-image: url('../media/svg/files/blank-image-dark.svg');
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="image-input image-input-empty image-input-outline image-input-placeholder mb-3"
|
||||
data-kt-image-input="true">
|
||||
|
||||
|
||||
@if ($itemView->image_url && $itemView->image_name)
|
||||
<div class="image-input-wrapper w-150px h-150px"
|
||||
style="background-image: url('{{ $itemView->image_url . '/thumbnail/' . $itemView->image_name }}')">
|
||||
</div>
|
||||
@else
|
||||
<div class="image-input-wrapper w-150px h-150px"></div>
|
||||
@endif
|
||||
|
||||
<label
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="change" data-bs-toggle="tooltip"
|
||||
title="Change avatar">
|
||||
|
||||
<i class="bi bi-pencil-fill fs-7"></i>
|
||||
|
||||
<input type="file" name="avatar" accept=".png, .jpg, .jpeg" />
|
||||
<input type="hidden" name="avatar_remove" />
|
||||
|
||||
</label>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="cancel" data-bs-toggle="tooltip"
|
||||
title="Cancel avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="remove" data-bs-toggle="tooltip"
|
||||
title="Remove avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="text-muted fs-7">Set the profile picture. Only *.png, *.jpg and *.jpeg
|
||||
image
|
||||
files are accepted</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-header" style="border: unset;">
|
||||
<!--begin::Card title-->
|
||||
<div class="required card-title">
|
||||
<h2>Active</h2>
|
||||
</div>
|
||||
<!--end::Card title-->
|
||||
</div>
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<label class="form-check form-switch form-check-custom form-check-solid">
|
||||
<input class="form-check-input" name="active" type="checkbox" value="1"
|
||||
{{ $itemView->active == 1 ? 'checked' : '' }} />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{{-- Right --}}
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Sub Categories</label>
|
||||
<div class="d-flex align-items-center mt-3">
|
||||
@foreach ($subCategoriesView as $item)
|
||||
<label
|
||||
class="form-check form-check-custom form-check-inline form-check-solid me-5 is-invalid">
|
||||
<input class="form-check-input" name="sub_categories[]" type="checkbox"
|
||||
value="{{ $item->id }}"
|
||||
@if (in_array($item->id, explode(',', $itemView->sub_category_ids))) checked @endif>
|
||||
<span class="fw-semibold ps-2 fs-6">
|
||||
{{ $item->name . '(' . $item->name_en . ')' }}
|
||||
</span>
|
||||
</label>
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<div class="position-relative d-flex align-items-center">
|
||||
<span class="svg-icon svg-icon-2 position-absolute mx-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21 22H3C2.4 22 2 21.6 2 21V5C2 4.4 2.4 4 3 4H21C21.6 4 22 4.4 22 5V21C22 21.6 21.6 22 21 22Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M6 6C5.4 6 5 5.6 5 5V3C5 2.4 5.4 2 6 2C6.6 2 7 2.4 7 3V5C7 5.6 6.6 6 6 6ZM11 5V3C11 2.4 10.6 2 10 2C9.4 2 9 2.4 9 3V5C9 5.6 9.4 6 10 6C10.6 6 11 5.6 11 5ZM15 5V3C15 2.4 14.6 2 14 2C13.4 2 13 2.4 13 3V5C13 5.6 13.4 6 14 6C14.6 6 15 5.6 15 5ZM19 5V3C19 2.4 18.6 2 18 2C17.4 2 17 2.4 17 3V5C17 5.6 17.4 6 18 6C18.6 6 19 5.6 19 5Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M8.8 13.1C9.2 13.1 9.5 13 9.7 12.8C9.9 12.6 10.1 12.3 10.1 11.9C10.1 11.6 10 11.3 9.8 11.1C9.6 10.9 9.3 10.8 9 10.8C8.8 10.8 8.59999 10.8 8.39999 10.9C8.19999 11 8.1 11.1 8 11.2C7.9 11.3 7.8 11.4 7.7 11.6C7.6 11.8 7.5 11.9 7.5 12.1C7.5 12.2 7.4 12.2 7.3 12.3C7.2 12.4 7.09999 12.4 6.89999 12.4C6.69999 12.4 6.6 12.3 6.5 12.2C6.4 12.1 6.3 11.9 6.3 11.7C6.3 11.5 6.4 11.3 6.5 11.1C6.6 10.9 6.8 10.7 7 10.5C7.2 10.3 7.49999 10.1 7.89999 10C8.29999 9.90003 8.60001 9.80003 9.10001 9.80003C9.50001 9.80003 9.80001 9.90003 10.1 10C10.4 10.1 10.7 10.3 10.9 10.4C11.1 10.5 11.3 10.8 11.4 11.1C11.5 11.4 11.6 11.6 11.6 11.9C11.6 12.3 11.5 12.6 11.3 12.9C11.1 13.2 10.9 13.5 10.6 13.7C10.9 13.9 11.2 14.1 11.4 14.3C11.6 14.5 11.8 14.7 11.9 15C12 15.3 12.1 15.5 12.1 15.8C12.1 16.2 12 16.5 11.9 16.8C11.8 17.1 11.5 17.4 11.3 17.7C11.1 18 10.7 18.2 10.3 18.3C9.9 18.4 9.5 18.5 9 18.5C8.5 18.5 8.1 18.4 7.7 18.2C7.3 18 7 17.8 6.8 17.6C6.6 17.4 6.4 17.1 6.3 16.8C6.2 16.5 6.10001 16.3 6.10001 16.1C6.10001 15.9 6.2 15.7 6.3 15.6C6.4 15.5 6.6 15.4 6.8 15.4C6.9 15.4 7.00001 15.4 7.10001 15.5C7.20001 15.6 7.3 15.6 7.3 15.7C7.5 16.2 7.7 16.6 8 16.9C8.3 17.2 8.6 17.3 9 17.3C9.2 17.3 9.5 17.2 9.7 17.1C9.9 17 10.1 16.8 10.3 16.6C10.5 16.4 10.5 16.1 10.5 15.8C10.5 15.3 10.4 15 10.1 14.7C9.80001 14.4 9.50001 14.3 9.10001 14.3C9.00001 14.3 8.9 14.3 8.7 14.3C8.5 14.3 8.39999 14.3 8.39999 14.3C8.19999 14.3 7.99999 14.2 7.89999 14.1C7.79999 14 7.7 13.8 7.7 13.7C7.7 13.5 7.79999 13.4 7.89999 13.2C7.99999 13 8.2 13 8.5 13H8.8V13.1ZM15.3 17.5V12.2C14.3 13 13.6 13.3 13.3 13.3C13.1 13.3 13 13.2 12.9 13.1C12.8 13 12.7 12.8 12.7 12.6C12.7 12.4 12.8 12.3 12.9 12.2C13 12.1 13.2 12 13.6 11.8C14.1 11.6 14.5 11.3 14.7 11.1C14.9 10.9 15.2 10.6 15.5 10.3C15.8 10 15.9 9.80003 15.9 9.70003C15.9 9.60003 16.1 9.60004 16.3 9.60004C16.5 9.60004 16.7 9.70003 16.8 9.80003C16.9 9.90003 17 10.2 17 10.5V17.2C17 18 16.7 18.4 16.2 18.4C16 18.4 15.8 18.3 15.6 18.2C15.4 18.1 15.3 17.8 15.3 17.5Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
<input class="form-control form-control-solid ps-12" type="text"
|
||||
id="due_date" name="due_date"
|
||||
value="{{ $itemView->due_date ? date('d-m-Y', strtotime($itemView->due_date)) : '' }}">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Subject</label>
|
||||
<input type="text" name="name" class="form-control mb-2 col-6"
|
||||
value="{{ $itemView->name }}" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Subject (EN)</label>
|
||||
<input type="text" name="name_en" class="form-control mb-2 col-6"
|
||||
value="{{ $itemView->name_en }}" />
|
||||
</div>
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Description</label>
|
||||
<div class="form-control" id="description" name="description"></div>
|
||||
<input type="hidden" id="description_input" name="description" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Description (EN)</label>
|
||||
<div class="form-control" id="description_en" name="description_en"></div>
|
||||
<input type="hidden" id="description_input_en" name="description_en" />
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('no-where-else/article') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button type="button" id="btn_submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
$('#due_date').flatpickr({
|
||||
enableTime: false,
|
||||
dateFormat: 'd-m-Y',
|
||||
defaultDate: null, // Do not preselect any date
|
||||
onReady: function(selectedDates, dateStr, instance) {
|
||||
// Highlight today's date with a custom CSS class
|
||||
const today = instance.todayDateElem;
|
||||
today.classList.add('flatpickr-today-highlight'); // Add a custom class to today
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on("click", "#btn_submit", function(e) {
|
||||
e.preventDefault();
|
||||
alertLoading("Loading")
|
||||
const form = $('#frmUpdate');
|
||||
form.submit();
|
||||
})
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<!-- Include Editor.js core -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest"></script>
|
||||
|
||||
<!-- Include the plugins -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/header"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/list"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/image"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/editorjs-inline-image"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/embed"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/editorjs-break-line"></script>
|
||||
|
||||
<script>
|
||||
// Custom video tool for embedding videos
|
||||
class VideoTool {
|
||||
constructor({
|
||||
data
|
||||
}) {
|
||||
this.data = data || {};
|
||||
}
|
||||
|
||||
// Render input for video URL
|
||||
render() {
|
||||
const wrapper = document.createElement("div");
|
||||
|
||||
const input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.placeholder = "Enter video URL";
|
||||
input.value = this.data.url || "";
|
||||
input.style.width = "100%";
|
||||
|
||||
const video = document.createElement("video");
|
||||
video.controls = true;
|
||||
video.style.width = "100%";
|
||||
video.style.marginTop = "10px";
|
||||
video.src = this.data.url || "";
|
||||
|
||||
input.addEventListener("input", (event) => {
|
||||
const value = event.target.value;
|
||||
this.data.url = value;
|
||||
video.src = value;
|
||||
});
|
||||
|
||||
wrapper.appendChild(input);
|
||||
wrapper.appendChild(video);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
// Save the video URL
|
||||
save(blockContent) {
|
||||
const input = blockContent.querySelector("input");
|
||||
return {
|
||||
url: input.value,
|
||||
};
|
||||
}
|
||||
|
||||
// Editor.js toolbox definition
|
||||
static get toolbox() {
|
||||
return {
|
||||
title: "Video",
|
||||
icon: '<svg width="20" height="20" viewBox="0 0 24 24"><path d="M10 8.64L15.27 12 10 15.36V8.64M10 3.14L21 12 10 20.86V3.14M3 4h4v16H3V4z"></path></svg>',
|
||||
};
|
||||
}
|
||||
}
|
||||
class YoutubeEmbed {
|
||||
/**
|
||||
* Define the toolbox settings for the Editor.js toolbar.
|
||||
*/
|
||||
static get toolbox() {
|
||||
return {
|
||||
title: "YouTube",
|
||||
icon: '<svg width="18" height="18" viewBox="0 0 24 24"><path d="M19.615 3.184c-.403-1.516-1.589-2.693-3.09-3.091-2.719-.727-13.525-.727-16.244 0-1.514.398-2.687 1.57-3.09 3.091-.727 2.719-.727 13.525 0 16.244.403 1.514 1.576 2.693 3.09 3.09 2.719.727 13.525.727 16.244 0 1.516-.397 2.692-1.576 3.09-3.09.727-2.719.727-13.525 0-16.244zm-11.615 13.316v-8l8 4-8 4z"/></svg>',
|
||||
};
|
||||
}
|
||||
|
||||
constructor({
|
||||
data,
|
||||
config,
|
||||
api,
|
||||
readOnly
|
||||
}) {
|
||||
this.data = data || {};
|
||||
this.readOnly = readOnly;
|
||||
this.wrapper = null;
|
||||
this.url = this.data.url || '';
|
||||
this.isEdited = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the input field and YouTube preview.
|
||||
*/
|
||||
render() {
|
||||
this.wrapper = document.createElement('div');
|
||||
this.wrapper.classList.add('block-wrapper');
|
||||
|
||||
const input = document.createElement('input');
|
||||
input.value = this.url;
|
||||
input.placeholder = "Paste YouTube URL here...";
|
||||
input.style.width = '100%';
|
||||
|
||||
this.wrapper.appendChild(input);
|
||||
this._createIframe(this.url);
|
||||
|
||||
input.addEventListener('change', (event) => {
|
||||
this.isEdited = true;
|
||||
this.url = event.target.value;
|
||||
this._createIframe(this.url);
|
||||
});
|
||||
|
||||
return this.wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the iframe for the YouTube video.
|
||||
*/
|
||||
_createIframe(url) {
|
||||
const videoId = this._extractVideoID(url);
|
||||
if (!videoId) {
|
||||
if (this.isEdited) {
|
||||
this.wrapper.querySelector('input').classList.add('invalid');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.wrapper.innerHTML = ''; // Clear the wrapper
|
||||
|
||||
const plyrContainer = document.createElement('div');
|
||||
plyrContainer.classList.add('video-wrapper');
|
||||
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.src = `https://www.youtube.com/embed/${videoId}`;
|
||||
iframe.allowFullscreen = true;
|
||||
|
||||
plyrContainer.appendChild(iframe);
|
||||
this.wrapper.appendChild(plyrContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the YouTube video ID from the URL.
|
||||
*/
|
||||
_extractVideoID(url) {
|
||||
const regex = /(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/)([^&?/]+)/;
|
||||
const match = url.match(regex);
|
||||
return match ? match[1] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the saved data for this block.
|
||||
*/
|
||||
save(blockContent) {
|
||||
return {
|
||||
url: this.url,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the core that this tool supports read-only mode.
|
||||
*/
|
||||
static get isReadOnlySupported() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
||||
const baseUrlUpload = "{{ url('no-where-else/article-upload-image') }}";
|
||||
const tools = {
|
||||
header: {
|
||||
class: Header,
|
||||
inlineToolbar: ['link', 'bold', 'italic'],
|
||||
config: {
|
||||
placeholder: 'Enter a header',
|
||||
levels: [2, 3, 4], // Set header levels
|
||||
defaultLevel: 3,
|
||||
},
|
||||
},
|
||||
breakLine: {
|
||||
class: BreakLine,
|
||||
inlineToolbar: true,
|
||||
shortcut: 'CMD+SHIFT+ENTER',
|
||||
},
|
||||
youtube: YoutubeEmbed,
|
||||
embed: {
|
||||
class: Embed,
|
||||
inlineToolbar: true,
|
||||
config: {
|
||||
services: {
|
||||
youtube: true,
|
||||
vimeo: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
video: {
|
||||
class: VideoTool,
|
||||
inlineToolbar: true,
|
||||
},
|
||||
image: {
|
||||
class: ImageTool,
|
||||
config: {
|
||||
endpoints: {
|
||||
byFile: baseUrlUpload,
|
||||
byUrl: baseUrlUpload,
|
||||
},
|
||||
field: 'image',
|
||||
types: 'image/*',
|
||||
inlineToolbar: true,
|
||||
additionalRequestHeaders: {
|
||||
'X-CSRF-TOKEN': csrfToken, // Include CSRF token here
|
||||
},
|
||||
enableResizing: true, // This is hypothetical; check if your tool supports this
|
||||
|
||||
},
|
||||
},
|
||||
inlineImage: {
|
||||
class: InlineImage,
|
||||
inlineToolbar: true,
|
||||
config: {
|
||||
embed: {
|
||||
display: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const descriptionData = {!! json_encode($itemView->description) !!};
|
||||
const editorDescription = new EditorJS({
|
||||
holder: 'description',
|
||||
tools: tools,
|
||||
data: descriptionData != "" ? JSON.parse(descriptionData) : {},
|
||||
onChange: () => {
|
||||
saveData(editorDescription, 'description_input')
|
||||
}
|
||||
});
|
||||
|
||||
const descriptionDataEn = {!! json_encode($itemView->description_en) !!};
|
||||
const editorDescriptionEn = new EditorJS({
|
||||
holder: 'description_en',
|
||||
tools: tools,
|
||||
data: descriptionDataEn !== "" ? JSON.parse(descriptionDataEn) : {},
|
||||
onChange: () => {
|
||||
saveData(editorDescriptionEn, 'description_input_en');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Function to save data to hidden inputs
|
||||
function saveData(editor, inputId) {
|
||||
editor.save().then((outputData) => {
|
||||
document.getElementById(inputId).value = JSON.stringify(outputData);
|
||||
}).catch((error) => {
|
||||
console.error('Saving failed: ', error);
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '#btn_submit', function(e) {
|
||||
e.preventDefault(); // Prevent default form submission
|
||||
|
||||
alertLoading("Loading..."); // Show loading alert (your custom function)
|
||||
|
||||
// Save both editor contents
|
||||
Promise.all([editorDescription.save(), editorDescriptionEn.save()])
|
||||
.then(([descriptionData, descriptionEnData]) => {
|
||||
// Store the JSON output in the hidden input fields
|
||||
$('#description_input').val(JSON.stringify(descriptionData));
|
||||
$('#description_input_en').val(JSON.stringify(descriptionEnData));
|
||||
|
||||
// Submit the form after saving the data
|
||||
$('#frmUpdate').submit();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error saving editor content:', error);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,411 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.breadcrumbList', [
|
||||
'title' => 'CHIANG MAI AND NOWHERE ELSE : Article Management',
|
||||
'pageName' => 'Article Management',
|
||||
])
|
||||
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<!--begin::Content container-->
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
<!--begin::Card-->
|
||||
<div class="card">
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<!--begin::Card header-->
|
||||
<div class="card-header border-0 pt-6">
|
||||
<!--begin::Card title-->
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
</div>
|
||||
|
||||
|
||||
@if (Auth::user()->role != 2)
|
||||
<div class="card-toolbar">
|
||||
<div class="d-flex justify-content-end" data-kt-customer-table-toolbar="base">
|
||||
<a href="{{ url('no-where-else/add-article') }}" class="btn btn-primary">Add
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card-header border-0 pt-5">
|
||||
|
||||
<div class="card-title">
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
<span class="svg-icon svg-icon-1 position-absolute ms-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<rect opacity="0.5" x="17.0365" y="15.1223" width="8.15546" height="2"
|
||||
rx="1" transform="rotate(45 17.0365 15.1223)" fill="currentColor">
|
||||
</rect>
|
||||
<path
|
||||
d="M11 19C6.55556 19 3 15.4444 3 11C3 6.55556 6.55556 3 11 3C15.4444 3 19 6.55556 19 11C19 15.4444 15.4444 19 11 19ZM11 5C7.53333 5 5 7.53333 5 11C5 14.4667 7.53333 17 11 17C14.4667 17 17 14.4667 17 11C17 7.53333 14.4667 5 11 5Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<input type="text" table-filter="search"
|
||||
class="form-control form-control-solid w-250px ps-15" placeholder="Search" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-toolbar flex-row-fluid justify-content-end gap-5">
|
||||
|
||||
<div class="w-100 mw-150px">
|
||||
<div class="position-relative d-flex align-items-center">
|
||||
<span class="svg-icon svg-icon-2 position-absolute mx-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21 22H3C2.4 22 2 21.6 2 21V5C2 4.4 2.4 4 3 4H21C21.6 4 22 4.4 22 5V21C22 21.6 21.6 22 21 22Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M6 6C5.4 6 5 5.6 5 5V3C5 2.4 5.4 2 6 2C6.6 2 7 2.4 7 3V5C7 5.6 6.6 6 6 6ZM11 5V3C11 2.4 10.6 2 10 2C9.4 2 9 2.4 9 3V5C9 5.6 9.4 6 10 6C10.6 6 11 5.6 11 5ZM15 5V3C15 2.4 14.6 2 14 2C13.4 2 13 2.4 13 3V5C13 5.6 13.4 6 14 6C14.6 6 15 5.6 15 5ZM19 5V3C19 2.4 18.6 2 18 2C17.4 2 17 2.4 17 3V5C17 5.6 17.4 6 18 6C18.6 6 19 5.6 19 5Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M8.8 13.1C9.2 13.1 9.5 13 9.7 12.8C9.9 12.6 10.1 12.3 10.1 11.9C10.1 11.6 10 11.3 9.8 11.1C9.6 10.9 9.3 10.8 9 10.8C8.8 10.8 8.59999 10.8 8.39999 10.9C8.19999 11 8.1 11.1 8 11.2C7.9 11.3 7.8 11.4 7.7 11.6C7.6 11.8 7.5 11.9 7.5 12.1C7.5 12.2 7.4 12.2 7.3 12.3C7.2 12.4 7.09999 12.4 6.89999 12.4C6.69999 12.4 6.6 12.3 6.5 12.2C6.4 12.1 6.3 11.9 6.3 11.7C6.3 11.5 6.4 11.3 6.5 11.1C6.6 10.9 6.8 10.7 7 10.5C7.2 10.3 7.49999 10.1 7.89999 10C8.29999 9.90003 8.60001 9.80003 9.10001 9.80003C9.50001 9.80003 9.80001 9.90003 10.1 10C10.4 10.1 10.7 10.3 10.9 10.4C11.1 10.5 11.3 10.8 11.4 11.1C11.5 11.4 11.6 11.6 11.6 11.9C11.6 12.3 11.5 12.6 11.3 12.9C11.1 13.2 10.9 13.5 10.6 13.7C10.9 13.9 11.2 14.1 11.4 14.3C11.6 14.5 11.8 14.7 11.9 15C12 15.3 12.1 15.5 12.1 15.8C12.1 16.2 12 16.5 11.9 16.8C11.8 17.1 11.5 17.4 11.3 17.7C11.1 18 10.7 18.2 10.3 18.3C9.9 18.4 9.5 18.5 9 18.5C8.5 18.5 8.1 18.4 7.7 18.2C7.3 18 7 17.8 6.8 17.6C6.6 17.4 6.4 17.1 6.3 16.8C6.2 16.5 6.10001 16.3 6.10001 16.1C6.10001 15.9 6.2 15.7 6.3 15.6C6.4 15.5 6.6 15.4 6.8 15.4C6.9 15.4 7.00001 15.4 7.10001 15.5C7.20001 15.6 7.3 15.6 7.3 15.7C7.5 16.2 7.7 16.6 8 16.9C8.3 17.2 8.6 17.3 9 17.3C9.2 17.3 9.5 17.2 9.7 17.1C9.9 17 10.1 16.8 10.3 16.6C10.5 16.4 10.5 16.1 10.5 15.8C10.5 15.3 10.4 15 10.1 14.7C9.80001 14.4 9.50001 14.3 9.10001 14.3C9.00001 14.3 8.9 14.3 8.7 14.3C8.5 14.3 8.39999 14.3 8.39999 14.3C8.19999 14.3 7.99999 14.2 7.89999 14.1C7.79999 14 7.7 13.8 7.7 13.7C7.7 13.5 7.79999 13.4 7.89999 13.2C7.99999 13 8.2 13 8.5 13H8.8V13.1ZM15.3 17.5V12.2C14.3 13 13.6 13.3 13.3 13.3C13.1 13.3 13 13.2 12.9 13.1C12.8 13 12.7 12.8 12.7 12.6C12.7 12.4 12.8 12.3 12.9 12.2C13 12.1 13.2 12 13.6 11.8C14.1 11.6 14.5 11.3 14.7 11.1C14.9 10.9 15.2 10.6 15.5 10.3C15.8 10 15.9 9.80003 15.9 9.70003C15.9 9.60003 16.1 9.60004 16.3 9.60004C16.5 9.60004 16.7 9.70003 16.8 9.80003C16.9 9.90003 17 10.2 17 10.5V17.2C17 18 16.7 18.4 16.2 18.4C16 18.4 15.8 18.3 15.6 18.2C15.4 18.1 15.3 17.8 15.3 17.5Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
<input class="form-control form-control-solid ps-12" placeholder="From"
|
||||
id="due_date_from" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="w-100 mw-150px">
|
||||
<div class="position-relative d-flex align-items-center">
|
||||
<span class="svg-icon svg-icon-2 position-absolute mx-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21 22H3C2.4 22 2 21.6 2 21V5C2 4.4 2.4 4 3 4H21C21.6 4 22 4.4 22 5V21C22 21.6 21.6 22 21 22Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M6 6C5.4 6 5 5.6 5 5V3C5 2.4 5.4 2 6 2C6.6 2 7 2.4 7 3V5C7 5.6 6.6 6 6 6ZM11 5V3C11 2.4 10.6 2 10 2C9.4 2 9 2.4 9 3V5C9 5.6 9.4 6 10 6C10.6 6 11 5.6 11 5ZM15 5V3C15 2.4 14.6 2 14 2C13.4 2 13 2.4 13 3V5C13 5.6 13.4 6 14 6C14.6 6 15 5.6 15 5ZM19 5V3C19 2.4 18.6 2 18 2C17.4 2 17 2.4 17 3V5C17 5.6 17.4 6 18 6C18.6 6 19 5.6 19 5Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M8.8 13.1C9.2 13.1 9.5 13 9.7 12.8C9.9 12.6 10.1 12.3 10.1 11.9C10.1 11.6 10 11.3 9.8 11.1C9.6 10.9 9.3 10.8 9 10.8C8.8 10.8 8.59999 10.8 8.39999 10.9C8.19999 11 8.1 11.1 8 11.2C7.9 11.3 7.8 11.4 7.7 11.6C7.6 11.8 7.5 11.9 7.5 12.1C7.5 12.2 7.4 12.2 7.3 12.3C7.2 12.4 7.09999 12.4 6.89999 12.4C6.69999 12.4 6.6 12.3 6.5 12.2C6.4 12.1 6.3 11.9 6.3 11.7C6.3 11.5 6.4 11.3 6.5 11.1C6.6 10.9 6.8 10.7 7 10.5C7.2 10.3 7.49999 10.1 7.89999 10C8.29999 9.90003 8.60001 9.80003 9.10001 9.80003C9.50001 9.80003 9.80001 9.90003 10.1 10C10.4 10.1 10.7 10.3 10.9 10.4C11.1 10.5 11.3 10.8 11.4 11.1C11.5 11.4 11.6 11.6 11.6 11.9C11.6 12.3 11.5 12.6 11.3 12.9C11.1 13.2 10.9 13.5 10.6 13.7C10.9 13.9 11.2 14.1 11.4 14.3C11.6 14.5 11.8 14.7 11.9 15C12 15.3 12.1 15.5 12.1 15.8C12.1 16.2 12 16.5 11.9 16.8C11.8 17.1 11.5 17.4 11.3 17.7C11.1 18 10.7 18.2 10.3 18.3C9.9 18.4 9.5 18.5 9 18.5C8.5 18.5 8.1 18.4 7.7 18.2C7.3 18 7 17.8 6.8 17.6C6.6 17.4 6.4 17.1 6.3 16.8C6.2 16.5 6.10001 16.3 6.10001 16.1C6.10001 15.9 6.2 15.7 6.3 15.6C6.4 15.5 6.6 15.4 6.8 15.4C6.9 15.4 7.00001 15.4 7.10001 15.5C7.20001 15.6 7.3 15.6 7.3 15.7C7.5 16.2 7.7 16.6 8 16.9C8.3 17.2 8.6 17.3 9 17.3C9.2 17.3 9.5 17.2 9.7 17.1C9.9 17 10.1 16.8 10.3 16.6C10.5 16.4 10.5 16.1 10.5 15.8C10.5 15.3 10.4 15 10.1 14.7C9.80001 14.4 9.50001 14.3 9.10001 14.3C9.00001 14.3 8.9 14.3 8.7 14.3C8.5 14.3 8.39999 14.3 8.39999 14.3C8.19999 14.3 7.99999 14.2 7.89999 14.1C7.79999 14 7.7 13.8 7.7 13.7C7.7 13.5 7.79999 13.4 7.89999 13.2C7.99999 13 8.2 13 8.5 13H8.8V13.1ZM15.3 17.5V12.2C14.3 13 13.6 13.3 13.3 13.3C13.1 13.3 13 13.2 12.9 13.1C12.8 13 12.7 12.8 12.7 12.6C12.7 12.4 12.8 12.3 12.9 12.2C13 12.1 13.2 12 13.6 11.8C14.1 11.6 14.5 11.3 14.7 11.1C14.9 10.9 15.2 10.6 15.5 10.3C15.8 10 15.9 9.80003 15.9 9.70003C15.9 9.60003 16.1 9.60004 16.3 9.60004C16.5 9.60004 16.7 9.70003 16.8 9.80003C16.9 9.90003 17 10.2 17 10.5V17.2C17 18 16.7 18.4 16.2 18.4C16 18.4 15.8 18.3 15.6 18.2C15.4 18.1 15.3 17.8 15.3 17.5Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
<input class="form-control form-control-solid ps-12" placeholder="To"
|
||||
id="due_date_to" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="button" id="btn-submit" class="btn btn-primary">
|
||||
Search
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body py-4">
|
||||
<!--begin::Table-->
|
||||
<table class="table align-middle table-row-dashed fs-6 gy-5" id="data-table-category">
|
||||
<!--begin::Table head-->
|
||||
<thead>
|
||||
<!--begin::Table row-->
|
||||
<tr class="text-start text-muted fw-bold fs-7 text-uppercase gs-0">
|
||||
<th class="min-w-125px">Pic</th>
|
||||
<th class="min-w-125px">Date</th>
|
||||
<th class="min-w-125px">Subject</th>
|
||||
<th class="min-w-125px">Subject (EN)</th>
|
||||
<th class="min-w-125px">Created</th>
|
||||
<th class="min-w-125px">Active</th>
|
||||
<th class="text-end min-w-100px">Manage</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="text-gray-600 fw-semibold">
|
||||
|
||||
@foreach ($itemView as $obj)
|
||||
<tr>
|
||||
<td class="d-flex align-items-center">
|
||||
<div class="symbol symbol-100px symbol-2by3 me-4">
|
||||
@if ($obj->image_url && $obj->image_name)
|
||||
<a class="show-image-preview d-block overlay"
|
||||
href="{{ url($obj->image_url . '/original/' . $obj->image_name) }}">
|
||||
<div class="symbol-label"
|
||||
style="background-image: url('{{ url($obj->image_url . '/thumbnail/' . $obj->image_name) }}')">
|
||||
</div>
|
||||
</a>
|
||||
@else
|
||||
<div class="symbol-label"
|
||||
style="background-image: url('{{ url('assets/media/avatars/blank.png') }}')">
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{{ Carbon\Carbon::parse($obj->due_date)->format('d, M Y') }}
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<a href="#" class="text-gray-800 text-hover-primary mb-1">
|
||||
{{ $obj->name }}
|
||||
</a>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<a href="#" class="text-gray-800 text-hover-primary mb-1">
|
||||
{{ $obj->name_en }}
|
||||
</a>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ Carbon\Carbon::parse($obj->created_at)->format('d, M Y') }}
|
||||
</td>
|
||||
|
||||
|
||||
<td>
|
||||
@if ($obj->active == 1)
|
||||
<span class="badge py-3 px-4 fs-7 badge-light-success">Active</span>
|
||||
@else
|
||||
<span class="badge py-3 px-4 fs-7 badge-light-danger">Inactive</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
||||
<td class="min-w-100px text-end">
|
||||
|
||||
{{-- View --}}
|
||||
{{-- <a href="{{ url('view-sub-category/' . $obj->id) }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm me-1">
|
||||
<span class="svg-icon svg-icon-2">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M17.5 11H6.5C4 11 2 9 2 6.5C2 4 4 2 6.5 2H17.5C20 2 22 4 22 6.5C22 9 20 11 17.5 11ZM15 6.5C15 7.9 16.1 9 17.5 9C18.9 9 20 7.9 20 6.5C20 5.1 18.9 4 17.5 4C16.1 4 15 5.1 15 6.5Z"
|
||||
fill="currentColor"></path>
|
||||
<path opacity="0.3"
|
||||
d="M17.5 22H6.5C4 22 2 20 2 17.5C2 15 4 13 6.5 13H17.5C20 13 22 15 22 17.5C22 20 20 22 17.5 22ZM4 17.5C4 18.9 5.1 20 6.5 20C7.9 20 9 18.9 9 17.5C9 16.1 7.9 15 6.5 15C5.1 15 4 16.1 4 17.5Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
</a> --}}
|
||||
|
||||
{{-- Edit --}}
|
||||
<a href="{{ url('no-where-else/edit-article/' . $obj->id) }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm me-1">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21.4 8.35303L19.241 10.511L13.485 4.755L15.643 2.59595C16.0248 2.21423 16.5426 1.99988 17.0825 1.99988C17.6224 1.99988 18.1402 2.21423 18.522 2.59595L21.4 5.474C21.7817 5.85581 21.9962 6.37355 21.9962 6.91345C21.9962 7.45335 21.7817 7.97122 21.4 8.35303ZM3.68699 21.932L9.88699 19.865L4.13099 14.109L2.06399 20.309C1.98815 20.5354 1.97703 20.7787 2.03189 21.0111C2.08674 21.2436 2.2054 21.4561 2.37449 21.6248C2.54359 21.7934 2.75641 21.9115 2.989 21.9658C3.22158 22.0201 3.4647 22.0084 3.69099 21.932H3.68699Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M5.574 21.3L3.692 21.928C3.46591 22.0032 3.22334 22.0141 2.99144 21.9594C2.75954 21.9046 2.54744 21.7864 2.3789 21.6179C2.21036 21.4495 2.09202 21.2375 2.03711 21.0056C1.9822 20.7737 1.99289 20.5312 2.06799 20.3051L2.696 18.422L5.574 21.3ZM4.13499 14.105L9.891 19.861L19.245 10.507L13.489 4.75098L4.13499 14.105Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{{-- Delete --}}
|
||||
@if ($obj->active == 1 && Auth::user()->role != 2)
|
||||
<a href="#" data-id="{{ $obj->id }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm delete-item">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5 9C5 8.44772 5.44772 8 6 8H18C18.5523 8 19 8.44772 19 9V18C19 19.6569 17.6569 21 16 21H8C6.34315 21 5 19.6569 5 18V9Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M5 5C5 4.44772 5.44772 4 6 4H18C18.5523 4 19 4.44772 19 5V5C19 5.55228 18.5523 6 18 6H6C5.44772 6 5 5.55228 5 5V5Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M9 4C9 3.44772 9.44772 3 10 3H14C14.5523 3 15 3.44772 15 4V4H9V4Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
const baseUrl = "{{ url('no-where-else/article') }}";
|
||||
var datatable;
|
||||
datatable = $("#data-table-category").DataTable({
|
||||
"info": false,
|
||||
"order": [],
|
||||
"pageLength": 25,
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, 500, 1000],
|
||||
[10, 25, 50, 100, 500, 1000]
|
||||
]
|
||||
});
|
||||
|
||||
// Filter by search
|
||||
const filterSearch = document.querySelector('[table-filter="search"]');
|
||||
filterSearch.addEventListener('keyup', function(e) {
|
||||
datatable.search(e.target.value).draw();
|
||||
});
|
||||
|
||||
// filter by status
|
||||
const filterStatus = document.querySelector('[table-filter="status"]');
|
||||
$(filterStatus).on('change', e => {
|
||||
let value = e.target.value;
|
||||
if (value === 'all') {
|
||||
value = '';
|
||||
}
|
||||
datatable.column(4).search(value).draw();
|
||||
});
|
||||
|
||||
|
||||
// Remove
|
||||
$(document).on('click', '.delete-item', function() {
|
||||
swal.fire({
|
||||
allowOutsideClick: false,
|
||||
text: "Are you sure you would like to Delete?",
|
||||
icon: "warning",
|
||||
buttonsStyling: false,
|
||||
showDenyButton: true,
|
||||
confirmButtonText: "Yes",
|
||||
denyButtonText: 'No',
|
||||
customClass: {
|
||||
confirmButton: "btn btn-primary",
|
||||
denyButton: "btn btn-light-danger"
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
// set up ajax
|
||||
initAjaxSetupToken();
|
||||
|
||||
const ajaxProp = {
|
||||
url: "{{ url('no-where-else/delete-article') }}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
item_id: $(this).data('id')
|
||||
},
|
||||
};
|
||||
|
||||
$.ajax(ajaxProp).done(function(res) {
|
||||
if (res.status) {
|
||||
const url = "{{ url('no-where-else/article') }}";
|
||||
alertSuccessWithUrl('Notice', "Delete success", url);
|
||||
hideLoading();
|
||||
} else {
|
||||
alertFail('Notice', res.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
logAjaxError(xhr, status, error);
|
||||
alertFail('Notice', error.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
var today = new Date();
|
||||
var dateFormat = "d-m-Y";
|
||||
|
||||
var dueDateFrom = $("#due_date_from");
|
||||
var dueDateTo = $("#due_date_to");
|
||||
|
||||
const dateFrom = "{{ $fromDateView }}";
|
||||
const dateTo = "{{ $toDateView }}";
|
||||
|
||||
dueDateFrom.flatpickr({
|
||||
showClearButton: true,
|
||||
enableTime: false,
|
||||
dateFormat: dateFormat,
|
||||
maxDate: today,
|
||||
defaultDate: dateFrom,
|
||||
|
||||
});
|
||||
|
||||
dueDateTo.flatpickr({
|
||||
showClearButton: true,
|
||||
enableTime: false,
|
||||
dateFormat: dateFormat,
|
||||
maxDate: today,
|
||||
defaultDate: dateTo,
|
||||
|
||||
});
|
||||
|
||||
const clearDatePicker = () => {
|
||||
dueDateFrom.flatpickr().clear();
|
||||
dueDateTo.flatpickr().clear();
|
||||
|
||||
// Set the date format again after clearing
|
||||
dueDateFrom.flatpickr({
|
||||
dateFormat: dateFormat
|
||||
});
|
||||
dueDateTo.flatpickr({
|
||||
dateFormat: dateFormat
|
||||
});
|
||||
}
|
||||
|
||||
$('#btn-submit').on('click', (e) => {
|
||||
e.preventDefault(); // Prevent the default behavior of the anchor element
|
||||
|
||||
// from
|
||||
const fromDateSelected = $("#due_date_from").val();
|
||||
|
||||
// to
|
||||
const toDateSelected = $("#due_date_to").val();
|
||||
|
||||
if (fromDateSelected && toDateSelected) {
|
||||
var newUrl =
|
||||
`${baseUrl}/${fromDateSelected}/${toDateSelected}`;
|
||||
window.location.href = newUrl;
|
||||
} else {
|
||||
var newUrl = `${baseUrl}/all/all/`;
|
||||
window.location.href = newUrl;
|
||||
}
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,178 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'Category Add',
|
||||
'pageName' => 'Add',
|
||||
'pageParent' => 'Category Management',
|
||||
'pageParentLink' => url('category'),
|
||||
])
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
|
||||
<form class="form d-flex flex-column flex-lg-row" action="{{ url('category/insert') }}" method="post"
|
||||
enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
<div class="d-flex flex-column gap-7 gap-lg-10 w-100 w-lg-300px mb-7 me-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
<div class="card-body text-center pt-0">
|
||||
|
||||
<style>
|
||||
.image-input-placeholder {
|
||||
background-image: url('{{ url('assets/media/svg/files/blank-image.svg') }}');
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .image-input-placeholder {
|
||||
background-image: url('../media/svg/files/blank-image-dark.svg');
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="image-input image-input-empty image-input-outline image-input-placeholder mb-3"
|
||||
data-kt-image-input="true">
|
||||
|
||||
<div class="image-input-wrapper w-150px h-150px"></div>
|
||||
|
||||
<label
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="change" data-bs-toggle="tooltip"
|
||||
title="Change avatar">
|
||||
|
||||
<i class="bi bi-pencil-fill fs-7"></i>
|
||||
|
||||
<input type="file" name="avatar" accept=".png, .jpg, .jpeg" />
|
||||
<input type="hidden" name="avatar_remove" />
|
||||
|
||||
</label>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="cancel" data-bs-toggle="tooltip"
|
||||
title="Cancel avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="remove" data-bs-toggle="tooltip"
|
||||
title="Remove avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="text-muted fs-7">Set the profile picture. Only *.png, *.jpg and *.jpeg
|
||||
image
|
||||
files are accepted</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{-- Active --}}
|
||||
<div class="card-header" style="border: unset;">
|
||||
<div class="required card-title">
|
||||
<h2>Active</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<label class="form-check form-switch form-check-custom form-check-solid">
|
||||
<input class="form-check-input" disabled readonly name="active" type="checkbox"
|
||||
value="1" checked />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Name</label>
|
||||
<input type="text" name="name" class="form-control mb-2 col-6"
|
||||
value="{{ old('name') }}" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Name (EN)</label>
|
||||
<input type="text" name="name_en" class="form-control mb-2 col-6"
|
||||
value="{{ old('name_en') }}" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('category') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save Changes</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {});
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,186 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'Category Edit',
|
||||
'pageName' => 'Edit',
|
||||
'pageParent' => 'Category Management',
|
||||
'pageParentLink' => url('category'),
|
||||
])
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
|
||||
<form class="form d-flex flex-column flex-lg-row" action="{{ url('category/update') }}" method="post"
|
||||
enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="id" value="{{ $itemView->id }}">
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
{{-- Left --}}
|
||||
<div class="d-flex flex-column gap-7 gap-lg-10 w-100 w-lg-300px mb-7 me-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
<div class="card-body text-center pt-0">
|
||||
|
||||
<style>
|
||||
.image-input-placeholder {
|
||||
background-image: url('{{ url('assets/media/svg/files/blank-image.svg') }}');
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .image-input-placeholder {
|
||||
background-image: url('../media/svg/files/blank-image-dark.svg');
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="image-input image-input-empty image-input-outline image-input-placeholder mb-3"
|
||||
data-kt-image-input="true">
|
||||
|
||||
|
||||
@if ($itemView->image_url && $itemView->image_name)
|
||||
<div class="image-input-wrapper w-150px h-150px"
|
||||
style="background-image: url('{{ $itemView->image_url . '/thumbnail/' . $itemView->image_name }}')">
|
||||
</div>
|
||||
@else
|
||||
<div class="image-input-wrapper w-150px h-150px"></div>
|
||||
@endif
|
||||
|
||||
<label
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="change" data-bs-toggle="tooltip"
|
||||
title="Change avatar">
|
||||
|
||||
<i class="bi bi-pencil-fill fs-7"></i>
|
||||
|
||||
<input type="file" name="avatar" accept=".png, .jpg, .jpeg" />
|
||||
<input type="hidden" name="avatar_remove" />
|
||||
|
||||
</label>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="cancel" data-bs-toggle="tooltip"
|
||||
title="Cancel avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="remove" data-bs-toggle="tooltip"
|
||||
title="Remove avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="text-muted fs-7">Set the profile picture. Only *.png, *.jpg and *.jpeg
|
||||
image
|
||||
files are accepted</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-header" style="border: unset;">
|
||||
<div class="required card-title">
|
||||
<h2>Active</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body pt-0">
|
||||
<label class="form-check form-switch form-check-custom form-check-solid">
|
||||
<input class="form-check-input" name="active" type="checkbox" value="1"
|
||||
{{ $itemView->active == 1 ? 'checked' : '' }} />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{{-- Right --}}
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Name</label>
|
||||
<input type="text" name="name" class="form-control mb-2 col-6"
|
||||
value="{{ $itemView->name }}" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Name (EN)</label>
|
||||
<input type="text" name="name_en" class="form-control mb-2 col-6"
|
||||
value="{{ $itemView->name_en }}" />
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('category') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save Changes</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {});
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,270 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.breadcrumbList', [
|
||||
'title' => 'Category Management',
|
||||
'pageName' => 'Category Management',
|
||||
])
|
||||
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<!--begin::Content container-->
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
<!--begin::Card-->
|
||||
<div class="card">
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!--begin::Card header-->
|
||||
<div class="card-header border-0 pt-6">
|
||||
<!--begin::Card title-->
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
<span class="svg-icon svg-icon-1 position-absolute ms-6">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<rect opacity="0.5" x="17.0365" y="15.1223" width="8.15546" height="2"
|
||||
rx="1" transform="rotate(45 17.0365 15.1223)" fill="currentColor" />
|
||||
<path
|
||||
d="M11 19C6.55556 19 3 15.4444 3 11C3 6.55556 6.55556 3 11 3C15.4444 3 19 6.55556 19 11C19 15.4444 15.4444 19 11 19ZM11 5C7.53333 5 5 7.53333 5 11C5 14.4667 7.53333 17 11 17C14.4667 17 17 14.4667 17 11C17 7.53333 14.4667 5 11 5Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
<input type="text" table-filter="search"
|
||||
class="form-control form-control-solid w-250px ps-15" placeholder="Search" />
|
||||
</div>
|
||||
|
||||
<div class="card-toolbar">
|
||||
<div class="w-150px me-3">
|
||||
<select class="form-select form-select-solid" data-control="select2"
|
||||
data-hide-search="true" data-placeholder="Status" table-filter="status">
|
||||
<option></option>
|
||||
<option value="all">All</option>
|
||||
<option value="active">Active</option>
|
||||
<option value="inactive">Inactive</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end" data-kt-customer-table-toolbar="base">
|
||||
<a href="{{ url('category/add') }}" class="btn btn-primary">Add </a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card-body py-4">
|
||||
<!--begin::Table-->
|
||||
<table class="table align-middle table-row-dashed fs-6 gy-5" id="data-table-category">
|
||||
<!--begin::Table head-->
|
||||
<thead>
|
||||
<!--begin::Table row-->
|
||||
<tr class="text-start text-muted fw-bold fs-7 text-uppercase gs-0">
|
||||
<th class="min-w-125px">Pic</th>
|
||||
<th class="min-w-125px">Name</th>
|
||||
<th class="min-w-125px">Name (EN)</th>
|
||||
<th class="min-w-125px">Created</th>
|
||||
<th class="min-w-125px">Active</th>
|
||||
<th class="text-end min-w-100px">Actions</th>
|
||||
</tr>
|
||||
<!--end::Table row-->
|
||||
</thead>
|
||||
<!--end::Table head-->
|
||||
<!--begin::Table body-->
|
||||
<tbody class="text-gray-600 fw-semibold">
|
||||
|
||||
@foreach ($itemView as $obj)
|
||||
<!--begin::Table row-->
|
||||
<tr>
|
||||
<td class="d-flex align-items-center">
|
||||
<div class="symbol symbol-100px symbol-2by3 me-4">
|
||||
@if ($obj->image_url && $obj->image_name)
|
||||
<a class="show-image-preview d-block overlay"
|
||||
href="{{ url($obj->image_url . '/original/' . $obj->image_name) }}">
|
||||
<div class="symbol-label"
|
||||
style="background-image: url('{{ url($obj->image_url . '/thumbnail/' . $obj->image_name) }}')">
|
||||
</div>
|
||||
</a>
|
||||
@else
|
||||
<div class="symbol-label"
|
||||
style="background-image: url('{{ url('assets/media/avatars/blank.png') }}')">
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ $obj->name }}
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ $obj->name_en }}
|
||||
</td>
|
||||
|
||||
<td class="">{{ date('d M, Y', strtotime($obj->created_at)) }}</td>
|
||||
|
||||
|
||||
<td class="">
|
||||
@if ($obj->active == 1)
|
||||
<span class="badge py-3 px-4 fs-7 badge-light-success">Active</span>
|
||||
@else
|
||||
<span class="badge py-3 px-4 fs-7 badge-light-danger">Inactive</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
||||
<td class="min-w-100px text-end">
|
||||
|
||||
{{-- Edit --}}
|
||||
<a href="{{ url('category/edit/' . $obj->id) }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm me-1">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21.4 8.35303L19.241 10.511L13.485 4.755L15.643 2.59595C16.0248 2.21423 16.5426 1.99988 17.0825 1.99988C17.6224 1.99988 18.1402 2.21423 18.522 2.59595L21.4 5.474C21.7817 5.85581 21.9962 6.37355 21.9962 6.91345C21.9962 7.45335 21.7817 7.97122 21.4 8.35303ZM3.68699 21.932L9.88699 19.865L4.13099 14.109L2.06399 20.309C1.98815 20.5354 1.97703 20.7787 2.03189 21.0111C2.08674 21.2436 2.2054 21.4561 2.37449 21.6248C2.54359 21.7934 2.75641 21.9115 2.989 21.9658C3.22158 22.0201 3.4647 22.0084 3.69099 21.932H3.68699Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M5.574 21.3L3.692 21.928C3.46591 22.0032 3.22334 22.0141 2.99144 21.9594C2.75954 21.9046 2.54744 21.7864 2.3789 21.6179C2.21036 21.4495 2.09202 21.2375 2.03711 21.0056C1.9822 20.7737 1.99289 20.5312 2.06799 20.3051L2.696 18.422L5.574 21.3ZM4.13499 14.105L9.891 19.861L19.245 10.507L13.489 4.75098L4.13499 14.105Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{{-- Delete --}}
|
||||
@if ($obj->active == 1)
|
||||
<a href="#" data-id="{{ $obj->id }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm delete-item">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5 9C5 8.44772 5.44772 8 6 8H18C18.5523 8 19 8.44772 19 9V18C19 19.6569 17.6569 21 16 21H8C6.34315 21 5 19.6569 5 18V9Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M5 5C5 4.44772 5.44772 4 6 4H18C18.5523 4 19 4.44772 19 5V5C19 5.55228 18.5523 6 18 6H6C5.44772 6 5 5.55228 5 5V5Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M9 4C9 3.44772 9.44772 3 10 3H14C14.5523 3 15 3.44772 15 4V4H9V4Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
var datatable;
|
||||
datatable = $("#data-table-category").DataTable({
|
||||
"info": false,
|
||||
"order": [],
|
||||
"pageLength": 25,
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, 500, 1000],
|
||||
[10, 25, 50, 100, 500, 1000]
|
||||
]
|
||||
});
|
||||
|
||||
// Filter by search
|
||||
const filterSearch = document.querySelector('[table-filter="search"]');
|
||||
filterSearch.addEventListener('keyup', function(e) {
|
||||
datatable.search(e.target.value).draw();
|
||||
});
|
||||
|
||||
// filter by status
|
||||
const filterStatus = document.querySelector('[table-filter="status"]');
|
||||
$(filterStatus).on('change', e => {
|
||||
let value = e.target.value;
|
||||
if (value === 'all') {
|
||||
value = '';
|
||||
}
|
||||
datatable.column(4).search(value).draw();
|
||||
});
|
||||
|
||||
|
||||
// Remove
|
||||
$(document).on('click', '.delete-item', function() {
|
||||
swal.fire({
|
||||
allowOutsideClick: false,
|
||||
text: "Are you sure you would like to Delete?",
|
||||
icon: "warning",
|
||||
buttonsStyling: false,
|
||||
showDenyButton: true,
|
||||
confirmButtonText: "Yes",
|
||||
denyButtonText: 'No',
|
||||
customClass: {
|
||||
confirmButton: "btn btn-primary",
|
||||
denyButton: "btn btn-light-danger"
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
// set up ajax
|
||||
initAjaxSetupToken();
|
||||
|
||||
const ajaxProp = {
|
||||
url: "{{ url('category/delete') }}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
item_id: $(this).data('id')
|
||||
},
|
||||
};
|
||||
|
||||
$.ajax(ajaxProp).done(function(res) {
|
||||
if (res.status) {
|
||||
const url = "{{ url('category') }}";
|
||||
alertSuccessWithUrl('Notice', "Delete success", url);
|
||||
hideLoading();
|
||||
} else {
|
||||
alertFail('Notice', res.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
logAjaxError(xhr, status, error);
|
||||
alertFail('Notice', error.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,316 @@
|
||||
@extends('layouts/backendTemplate')
|
||||
|
||||
@section('content')
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
<div id="kt_app_toolbar" class="app-toolbar py-3 py-lg-6">
|
||||
|
||||
<div id="kt_app_toolbar_container" class="app-container container-xxl d-flex flex-stack">
|
||||
|
||||
<div class="page-title d-flex flex-column justify-content-center flex-wrap me-3">
|
||||
|
||||
<h1 class="page-heading d-flex text-dark fw-bold fs-3 flex-column justify-content-center my-3">
|
||||
Dashboard
|
||||
</h1>
|
||||
|
||||
<ul class="breadcrumb breadcrumb-separatorless fw-semibold fs-7 my-0 pt-1">
|
||||
|
||||
<li class="breadcrumb-item text-muted">
|
||||
<a href="{{ url('') }}" class="text-muted text-hover-primary">
|
||||
Dashboard
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<!--begin::Content container-->
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
<!--begin::Row-->
|
||||
|
||||
@if ($itemView['sub_category_no_where_else'])
|
||||
<h1>CHIANG MAI AND NOWHERE ELSE</h1>
|
||||
<div class="row gy-5 g-xl-10">
|
||||
@foreach ($itemView['sub_category_no_where_else'] as $item)
|
||||
<div class="col-sm-6 col-xl-2 mb-xl-10">
|
||||
<div class="card h-lg-100">
|
||||
<div class="card-body d-flex justify-content-between align-items-start flex-column">
|
||||
|
||||
<div class="m-0">
|
||||
<span class="svg-icon svg-icon-2hx svg-icon-gray-600">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M14 3V21H10V3C10 2.4 10.4 2 11 2H13C13.6 2 14 2.4 14 3ZM7 14H5C4.4 14 4 14.4 4 15V21H8V15C8 14.4 7.6 14 7 14Z"
|
||||
fill="currentColor"></path>
|
||||
<path
|
||||
d="M21 20H20V8C20 7.4 19.6 7 19 7H17C16.4 7 16 7.4 16 8V20H3C2.4 20 2 20.4 2 21C2 21.6 2.4 22 3 22H21C21.6 22 22 21.6 22 21C22 20.4 21.6 20 21 20Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column my-7">
|
||||
|
||||
<span class="fw-semibold fs-3x text-gray-800 lh-1 ls-n2">
|
||||
{{ number_format($item['article_count'], 0) }}
|
||||
</span>
|
||||
|
||||
<div class="m-0">
|
||||
<span class="fw-semibold fs-6 text-gray-400">
|
||||
{{ $item['name'] ?? '-' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
@if ($itemView['sub_category_where_else'])
|
||||
<h1>WHERE ELSE</h1>
|
||||
<div class="row gy-5 g-xl-10">
|
||||
@foreach ($itemView['sub_category_where_else'] as $item)
|
||||
<div class="col-sm-6 col-xl-2 mb-xl-10">
|
||||
<div class="card h-lg-100">
|
||||
<div class="card-body d-flex justify-content-between align-items-start flex-column">
|
||||
|
||||
<div class="m-0">
|
||||
<span class="svg-icon svg-icon-2hx svg-icon-gray-600">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M14 3V21H10V3C10 2.4 10.4 2 11 2H13C13.6 2 14 2.4 14 3ZM7 14H5C4.4 14 4 14.4 4 15V21H8V15C8 14.4 7.6 14 7 14Z"
|
||||
fill="currentColor"></path>
|
||||
<path
|
||||
d="M21 20H20V8C20 7.4 19.6 7 19 7H17C16.4 7 16 7.4 16 8V20H3C2.4 20 2 20.4 2 21C2 21.6 2.4 22 3 22H21C21.6 22 22 21.6 22 21C22 20.4 21.6 20 21 20Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column my-7">
|
||||
|
||||
<span class="fw-semibold fs-3x text-gray-800 lh-1 ls-n2">
|
||||
{{ number_format($item['article_count'], 0) }}
|
||||
</span>
|
||||
|
||||
<div class="m-0">
|
||||
<span class="fw-semibold fs-6 text-gray-400">
|
||||
{{ $item['name'] ?? '-' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<h1>FILES</h1>
|
||||
<div class="row gy-5 g-xl-10">
|
||||
|
||||
<div class="col-sm-6 col-xl-2 mb-xl-10">
|
||||
<!--begin::Card widget 2-->
|
||||
<div class="card h-lg-100">
|
||||
<!--begin::Body-->
|
||||
<div class="card-body d-flex justify-content-between align-items-start flex-column">
|
||||
<!--begin::Icon-->
|
||||
<div class="m-0">
|
||||
<!--begin::Svg Icon | path: icons/duotune/graphs/gra001.svg-->
|
||||
<span class="svg-icon svg-icon-2hx svg-icon-gray-600">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M14 3V21H10V3C10 2.4 10.4 2 11 2H13C13.6 2 14 2.4 14 3ZM7 14H5C4.4 14 4 14.4 4 15V21H8V15C8 14.4 7.6 14 7 14Z"
|
||||
fill="currentColor"></path>
|
||||
<path
|
||||
d="M21 20H20V8C20 7.4 19.6 7 19 7H17C16.4 7 16 7.4 16 8V20H3C2.4 20 2 20.4 2 21C2 21.6 2.4 22 3 22H21C21.6 22 22 21.6 22 21C22 20.4 21.6 20 21 20Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<!--end::Svg Icon-->
|
||||
</div>
|
||||
<!--end::Icon-->
|
||||
<!--begin::Section-->
|
||||
<div class="d-flex flex-column my-7">
|
||||
<!--begin::Number-->
|
||||
<span class="fw-semibold fs-3x text-gray-800 lh-1 ls-n2">
|
||||
{{ number_format($countVideoView, 0) }}
|
||||
</span>
|
||||
<!--end::Number-->
|
||||
<!--begin::Follower-->
|
||||
<div class="m-0">
|
||||
<span class="fw-semibold fs-6 text-gray-400">Video</span>
|
||||
</div>
|
||||
<!--end::Follower-->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!--end::Body-->
|
||||
</div>
|
||||
<!--end::Card widget 2-->
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6 col-xl-2 mb-xl-10">
|
||||
<!--begin::Card widget 2-->
|
||||
<div class="card h-lg-100">
|
||||
<!--begin::Body-->
|
||||
<div class="card-body d-flex justify-content-between align-items-start flex-column">
|
||||
<!--begin::Icon-->
|
||||
<div class="m-0">
|
||||
<!--begin::Svg Icon | path: icons/duotune/graphs/gra001.svg-->
|
||||
<span class="svg-icon svg-icon-2hx svg-icon-gray-600">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M14 3V21H10V3C10 2.4 10.4 2 11 2H13C13.6 2 14 2.4 14 3ZM7 14H5C4.4 14 4 14.4 4 15V21H8V15C8 14.4 7.6 14 7 14Z"
|
||||
fill="currentColor"></path>
|
||||
<path
|
||||
d="M21 20H20V8C20 7.4 19.6 7 19 7H17C16.4 7 16 7.4 16 8V20H3C2.4 20 2 20.4 2 21C2 21.6 2.4 22 3 22H21C21.6 22 22 21.6 22 21C22 20.4 21.6 20 21 20Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<!--end::Svg Icon-->
|
||||
</div>
|
||||
<!--end::Icon-->
|
||||
<!--begin::Section-->
|
||||
<div class="d-flex flex-column my-7">
|
||||
<!--begin::Number-->
|
||||
<span class="fw-semibold fs-3x text-gray-800 lh-1 ls-n2">
|
||||
{{ number_format($countSoundView, 0) }}
|
||||
</span>
|
||||
<!--end::Number-->
|
||||
<!--begin::Follower-->
|
||||
<div class="m-0">
|
||||
<span class="fw-semibold fs-6 text-gray-400">Sound</span>
|
||||
</div>
|
||||
<!--end::Follower-->
|
||||
</div>
|
||||
<!--end::Section-->
|
||||
|
||||
</div>
|
||||
<!--end::Body-->
|
||||
</div>
|
||||
<!--end::Card widget 2-->
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6 col-xl-2 mb-xl-10">
|
||||
<!--begin::Card widget 2-->
|
||||
<div class="card h-lg-100">
|
||||
<!--begin::Body-->
|
||||
<div class="card-body d-flex justify-content-between align-items-start flex-column">
|
||||
<!--begin::Icon-->
|
||||
<div class="m-0">
|
||||
<!--begin::Svg Icon | path: icons/duotune/graphs/gra001.svg-->
|
||||
<span class="svg-icon svg-icon-2hx svg-icon-gray-600">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M14 3V21H10V3C10 2.4 10.4 2 11 2H13C13.6 2 14 2.4 14 3ZM7 14H5C4.4 14 4 14.4 4 15V21H8V15C8 14.4 7.6 14 7 14Z"
|
||||
fill="currentColor"></path>
|
||||
<path
|
||||
d="M21 20H20V8C20 7.4 19.6 7 19 7H17C16.4 7 16 7.4 16 8V20H3C2.4 20 2 20.4 2 21C2 21.6 2.4 22 3 22H21C21.6 22 22 21.6 22 21C22 20.4 21.6 20 21 20Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<!--end::Svg Icon-->
|
||||
</div>
|
||||
<!--end::Icon-->
|
||||
<!--begin::Section-->
|
||||
<div class="d-flex flex-column my-7">
|
||||
<!--begin::Number-->
|
||||
<span class="fw-semibold fs-3x text-gray-800 lh-1 ls-n2">
|
||||
{{ number_format($countImageView, 0) }}
|
||||
</span>
|
||||
<!--end::Number-->
|
||||
<!--begin::Follower-->
|
||||
<div class="m-0">
|
||||
<span class="fw-semibold fs-6 text-gray-400">Images</span>
|
||||
</div>
|
||||
<!--end::Follower-->
|
||||
</div>
|
||||
<!--end::Section-->
|
||||
|
||||
</div>
|
||||
<!--end::Body-->
|
||||
</div>
|
||||
<!--end::Card widget 2-->
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-sm-6 col-xl-2 mb-xl-10">
|
||||
<!--begin::Card widget 2-->
|
||||
<div class="card h-lg-100">
|
||||
<!--begin::Body-->
|
||||
<div class="card-body d-flex justify-content-between align-items-start flex-column">
|
||||
<!--begin::Icon-->
|
||||
<div class="m-0">
|
||||
<!--begin::Svg Icon | path: icons/duotune/graphs/gra001.svg-->
|
||||
<span class="svg-icon svg-icon-2hx svg-icon-gray-600">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M14 3V21H10V3C10 2.4 10.4 2 11 2H13C13.6 2 14 2.4 14 3ZM7 14H5C4.4 14 4 14.4 4 15V21H8V15C8 14.4 7.6 14 7 14Z"
|
||||
fill="currentColor"></path>
|
||||
<path
|
||||
d="M21 20H20V8C20 7.4 19.6 7 19 7H17C16.4 7 16 7.4 16 8V20H3C2.4 20 2 20.4 2 21C2 21.6 2.4 22 3 22H21C21.6 22 22 21.6 22 21C22 20.4 21.6 20 21 20Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<!--end::Svg Icon-->
|
||||
</div>
|
||||
<!--end::Icon-->
|
||||
<!--begin::Section-->
|
||||
<div class="d-flex flex-column my-7">
|
||||
<!--begin::Number-->
|
||||
<span class="fw-semibold fs-3x text-gray-800 lh-1 ls-n2">
|
||||
{{ number_format($countDocumentView, 0) }}
|
||||
</span>
|
||||
<!--end::Number-->
|
||||
<!--begin::Follower-->
|
||||
<div class="m-0">
|
||||
<span class="fw-semibold fs-6 text-gray-400">Documents</span>
|
||||
</div>
|
||||
<!--end::Follower-->
|
||||
</div>
|
||||
<!--end::Section-->
|
||||
|
||||
</div>
|
||||
<!--end::Body-->
|
||||
</div>
|
||||
<!--end::Card widget 2-->
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!--end::Content container-->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
|
||||
@section('script')
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {});
|
||||
</script>
|
||||
@endsection
|
||||
@@ -0,0 +1,366 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<style>
|
||||
#progressBar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
border-radius: 5px;
|
||||
margin-top: 10px;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.progress-bar::-webkit-progress-value {
|
||||
background-color: #4CAF50;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
margin-top: 10px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'Document Add',
|
||||
'pageName' => 'Add',
|
||||
'pageParent' => 'Document Management',
|
||||
'pageParentLink' => url('document'),
|
||||
])
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
|
||||
|
||||
<form id="frmAdd" class="form d-flex flex-column flex-lg-row" method="post"
|
||||
enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<div class="mb-10">
|
||||
<label class="form-label required">File Document</label>
|
||||
|
||||
<input class="fileInput file-input" type="file" id="fileInput" name="fileInput"
|
||||
accept=".pdf, .xls, .doc, .docx, .pptx, .csv, .txt" multiple>
|
||||
|
||||
<progress id="progressBar" class="progress-bar" value="0"
|
||||
max="100"></progress>
|
||||
<div id="progressText" class="progress-text">0%</div>
|
||||
|
||||
<div class="text-muted fs-7">Allowed Types .pdf, .xls, .doc, .docx, .pptx, .csv,
|
||||
.txt</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('document') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button type="button" id="btn_submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script>
|
||||
const baseApiUrl = "{{ env('API_URL') }}";
|
||||
|
||||
|
||||
$(document).on("click", "#btn_submit", async function(e) {
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
await uploadFile();
|
||||
|
||||
});
|
||||
|
||||
|
||||
// Step 1
|
||||
async function uploadFile() {
|
||||
const fileInput = document.getElementById("fileInput");
|
||||
const progressBar = document.getElementById("progressBar");
|
||||
const progressText = document.getElementById("progressText");
|
||||
|
||||
if (!fileInput || fileInput.files.length === 0) {
|
||||
alertFail("Notice", "Please select one or more files.");
|
||||
hideLoading();
|
||||
return;
|
||||
}
|
||||
|
||||
const files = Array.from(fileInput.files); // Get all selected files
|
||||
$("#progressBar").show();
|
||||
|
||||
let totalSize = files.reduce((sum, file) => sum + file.size, 0);
|
||||
let totalUploadedSize = 0;
|
||||
|
||||
// Upload all files sequentially
|
||||
for (const file of files) {
|
||||
await uploadSingleFile(file, progressBar, progressText, totalSize, (fileUploadedSize) => {
|
||||
totalUploadedSize += fileUploadedSize;
|
||||
const overallPercent = Math.floor((totalUploadedSize / totalSize) * 100);
|
||||
animateProgress(progressBar, progressText, overallPercent);
|
||||
});
|
||||
}
|
||||
const folderId = "{{ $folderIdView }}";
|
||||
let redirectUrl = "{{ url('document') }}"
|
||||
if (folderId) {
|
||||
redirectUrl = `${redirectUrl}/folder/${folderId}`;
|
||||
}
|
||||
alertSuccessWithUrl("Notice", "All files uploaded successfully", redirectUrl);
|
||||
}
|
||||
|
||||
async function uploadSingleFile(file, progressBar, progressText, totalSize, updateOverallProgress) {
|
||||
const uploadId = await initiateMultipartUpload(file.name);
|
||||
const partSize = 500 * 1024 * 1024; // 500 MB per part
|
||||
const parts = [];
|
||||
let uploadedSize = 0;
|
||||
|
||||
const uploadPromises = Array.from({
|
||||
length: Math.ceil(file.size / partSize)
|
||||
},
|
||||
(_, index) => {
|
||||
const partNumber = index + 1;
|
||||
const chunk = file.slice(index * partSize, (index + 1) * partSize);
|
||||
|
||||
return (async () => {
|
||||
const presignedUrl = await getPresignedUrl(uploadId, partNumber, file.name);
|
||||
const etag = await uploadPartToS3(presignedUrl, chunk);
|
||||
|
||||
parts.push({
|
||||
PartNumber: partNumber,
|
||||
ETag: etag
|
||||
});
|
||||
|
||||
uploadedSize += chunk.size;
|
||||
updateOverallProgress(chunk.size); // Update the overall progress
|
||||
})();
|
||||
}
|
||||
);
|
||||
|
||||
await Promise.all(uploadPromises);
|
||||
await completeMultipartUpload(uploadId, parts, file.name);
|
||||
await saveFileNameToDB(file.name);
|
||||
}
|
||||
|
||||
// Step 2
|
||||
async function initiateMultipartUpload(fileName) {
|
||||
const urlUploadImage = `${baseApiUrl}/initiate-multipart-upload`;
|
||||
const response = await fetch(
|
||||
urlUploadImage, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
fileName
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
const {
|
||||
uploadId
|
||||
} = await response.json();
|
||||
|
||||
return uploadId;
|
||||
}
|
||||
|
||||
// Step 3
|
||||
async function getPresignedUrl(uploadId, partNumber, fileName) {
|
||||
|
||||
const urlPresigned = `${baseApiUrl}/get-presigned-url`
|
||||
const response = await fetch(
|
||||
urlPresigned, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
uploadId,
|
||||
partNumber,
|
||||
fileName
|
||||
}),
|
||||
}
|
||||
);
|
||||
const {
|
||||
url
|
||||
} = await response.json();
|
||||
return url;
|
||||
}
|
||||
|
||||
// Step 4
|
||||
async function uploadPartToS3(url, chunk) {
|
||||
const response = await fetch(url, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/octet-stream",
|
||||
},
|
||||
body: chunk,
|
||||
});
|
||||
if (!response.ok) {
|
||||
alertFail("Notice", "Failed to upload part")
|
||||
hideLoading();
|
||||
//throw new Error("Failed to upload part");
|
||||
}
|
||||
|
||||
const etag = `${response.headers.get("ETag")}`.replace(/"/g, "");
|
||||
|
||||
if (!etag) {
|
||||
throw new Error("Failed to retrieve ETag from the response.");
|
||||
}
|
||||
|
||||
return etag;
|
||||
}
|
||||
|
||||
// Step 5
|
||||
async function completeMultipartUpload(uploadId, parts, fileName) {
|
||||
const urlUploadComplete = `${baseApiUrl}/complete-multipart-upload`;
|
||||
const response = await fetch(urlUploadComplete, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
uploadId,
|
||||
parts,
|
||||
fileName
|
||||
}),
|
||||
});
|
||||
if (response.ok) {
|
||||
//window.location.href = "{{ url('image') }}";
|
||||
} else {
|
||||
alertFail("Notice", "Failed to upload part");
|
||||
hideLoading();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Smoothly animates the progress bar and percentage text.
|
||||
*/
|
||||
async function animateProgress(progressBar, progressText, targetPercent) {
|
||||
const currentPercent = parseInt(progressBar.value) || 0;
|
||||
// Increment the percentage smoothly
|
||||
for (let percent = currentPercent + 1; percent <= targetPercent; percent++) {
|
||||
progressBar.value = percent;
|
||||
progressText.textContent = `${percent}%`;
|
||||
|
||||
// Add a small delay to make the increment visible (10ms delay)
|
||||
await new Promise((resolve) => setTimeout(resolve, 10));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the uploaded file name to the server using AJAX.
|
||||
*/
|
||||
function saveFileNameToDB(fileName) {
|
||||
initAjaxSetupToken();
|
||||
|
||||
const folderId = "{{ $folderIdView }}";
|
||||
const url = "{{ url('') }}";
|
||||
|
||||
return $.ajax({
|
||||
url: `${url}/document/insert`,
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({
|
||||
fileName,
|
||||
folderId
|
||||
}),
|
||||
success: (response) => {
|
||||
console.log('File name saved:', response);
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Error saving file name:', err);
|
||||
alertFail("Notice", "There was an error saving the file name.");
|
||||
hideLoading();
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
$('.file-input').fileuploader({
|
||||
extensions: ['pdf', 'xls', 'doc', 'docx', 'pptx', 'csv', 'txt'],
|
||||
limit: null,
|
||||
fileMaxSize: null,
|
||||
changeInput: '<div class="fileuploader-input">' +
|
||||
'<div class="fileuploader-input-inner">' +
|
||||
'<p><i class="fileuploader-icon-main"></i></p>' +
|
||||
'<h6>Drag and drop files here</h6>' +
|
||||
'<p>or</p>' +
|
||||
'<br>' +
|
||||
'<button type="button" class="fileuploader-input-button"><span>${captions.button}</span></button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
theme: 'dragdrop',
|
||||
});
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,95 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'Document Create Folder',
|
||||
'pageName' => 'Create folder',
|
||||
'pageParent' => 'Document Management',
|
||||
'pageParentLink' => url('document'),
|
||||
])
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
<form id="frmAdd" action="{{ url('document/insert-folder') }}"
|
||||
class="form d-flex flex-column flex-lg-row" method="post" enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Name</label>
|
||||
<input type="text" name="name" class="form-control mb-2 col-6"
|
||||
value="{{ old('name') }}" />
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('document') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script></script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,96 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'Document Edit Folder',
|
||||
'pageName' => 'Edit folder',
|
||||
'pageParent' => 'Document Management',
|
||||
'pageParentLink' => url('document'),
|
||||
])
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
<form id="frmAdd" action="{{ url('document/update-folder') }}"
|
||||
class="form d-flex flex-column flex-lg-row" method="post" enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="id" value="{{ $idView }}">
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Name</label>
|
||||
<input type="text" name="name" class="form-control mb-2 col-6"
|
||||
value="{{ $itemView->name }}" />
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('document') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script></script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,324 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<style>
|
||||
.link-container {
|
||||
display: flex;
|
||||
/* Use flexbox for alignment */
|
||||
align-items: center;
|
||||
/* Center items vertically */
|
||||
justify-content: space-between;
|
||||
/* Space between the URL and button */
|
||||
}
|
||||
|
||||
.file-url {
|
||||
flex: 1;
|
||||
/* Allow the URL to take up available space */
|
||||
color: #007bff;
|
||||
/* Link color */
|
||||
text-decoration: none;
|
||||
/* Remove underline */
|
||||
overflow: hidden;
|
||||
/* Hide overflow */
|
||||
white-space: nowrap;
|
||||
/* Prevent text wrapping */
|
||||
text-overflow: ellipsis;
|
||||
/* Add ellipsis for overflow */
|
||||
margin-right: 10px;
|
||||
/* Space between text and button */
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.breadcrumbList', [
|
||||
'title' => 'Document Management Folder ' . $folderView->name,
|
||||
'pageName' => 'Document Management',
|
||||
])
|
||||
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
<div class="card">
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<div class="card-header border-0 pt-6">
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
</div>
|
||||
|
||||
@if (Auth::user()->role != 2)
|
||||
<div class="card-toolbar">
|
||||
<div class="d-flex justify-content-end" data-kt-customer-table-toolbar="base">
|
||||
<a href="{{ url('document/add/' . $folderView->id) }}" class="btn btn-primary">Add
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card-header border-0 pt-5">
|
||||
|
||||
<div class="card-title">
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
<span class="svg-icon svg-icon-1 position-absolute ms-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<rect opacity="0.5" x="17.0365" y="15.1223" width="8.15546" height="2"
|
||||
rx="1" transform="rotate(45 17.0365 15.1223)" fill="currentColor">
|
||||
</rect>
|
||||
<path
|
||||
d="M11 19C6.55556 19 3 15.4444 3 11C3 6.55556 6.55556 3 11 3C15.4444 3 19 6.55556 19 11C19 15.4444 15.4444 19 11 19ZM11 5C7.53333 5 5 7.53333 5 11C5 14.4667 7.53333 17 11 17C14.4667 17 17 14.4667 17 11C17 7.53333 14.4667 5 11 5Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<input type="text" table-filter="search"
|
||||
class="form-control form-control-solid w-250px ps-15" placeholder="Search" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-body py-4">
|
||||
<!--begin::Table-->
|
||||
<table class="table align-middle table-row-dashed fs-6 gy-5" id="data-table">
|
||||
<!--begin::Table head-->
|
||||
<thead>
|
||||
<!--begin::Table row-->
|
||||
<tr class="text-start text-muted fw-bold fs-7 text-uppercase gs-0">
|
||||
<th class="min-w-125px">Name</th>
|
||||
<th class="min-w-125px">Created</th>
|
||||
<th class="text-end min-w-100px">Manage</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="text-gray-600 fw-semibold">
|
||||
|
||||
@foreach ($itemView as $obj)
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<a href="#" class="text-gray-800 text-hover-primary">
|
||||
@if (isset($obj['name']) && Str::endsWith($obj['name'], ['.pdf']))
|
||||
<img alt="PDF Icon" class="w-30px me-3"
|
||||
src="{{ url('assets/media/svg/files/pdf.svg') }}">
|
||||
@elseif (isset($obj['name']) && Str::endsWith($obj['name'], ['.doc', '.docx']))
|
||||
<img alt="DOC Icon" class="w-30px me-3"
|
||||
src="{{ url('assets/media/svg/files/doc.svg') }}">
|
||||
@else
|
||||
<span class="svg-icon svg-icon-2x svg-icon-primary me-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M19 22H5C4.4 22 4 21.6 4 21V3C4 2.4 4.4 2 5 2H14L20 8V21C20 21.6 19.6 22 19 22Z"
|
||||
fill="currentColor"></path>
|
||||
<path d="M15 8H20L14 2V7C14 7.6 14.4 8 15 8Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
@endif
|
||||
{{ $obj['name'] }}
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
|
||||
|
||||
<td>
|
||||
{{ Carbon\Carbon::parse($obj['created_at'])->format('d, M Y') }}
|
||||
</td>
|
||||
|
||||
<td class="min-w-100px text-end">
|
||||
|
||||
{{-- Download --}}
|
||||
<a href="{{ env('R2_SCHEMA_URL') . $obj['name'] }}" target="_blank"
|
||||
class="btn btn-sm btn-icon btn-light btn-active-light-primary"
|
||||
type="button" data-bs-toggle="tooltip" aria-label="Coming soon"
|
||||
data-bs-original-title="Coming soon" data-kt-initialized="1">
|
||||
<i class="bi bi-download fs-3"></i>
|
||||
</a>
|
||||
|
||||
{{-- Copy --}}
|
||||
<button type="button" data-action="copy"
|
||||
data-url="{{ env('R2_SCHEMA_URL') . $obj['name'] }}"
|
||||
class="btn btn-sm btn-icon btn-light btn-active-light-primary copy-button">
|
||||
<span class="svg-icon svg-icon-2">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.5"
|
||||
d="M18 2H9C7.34315 2 6 3.34315 6 5H8C8 4.44772 8.44772 4 9 4H18C18.5523 4 19 4.44772 19 5V16C19 16.5523 18.5523 17 18 17V19C19.6569 19 21 17.6569 21 16V5C21 3.34315 19.6569 2 18 2Z"
|
||||
fill="currentColor"></path>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M14.7857 7.125H6.21429C5.62255 7.125 5.14286 7.6007 5.14286 8.1875V18.8125C5.14286 19.3993 5.62255 19.875 6.21429 19.875H14.7857C15.3774 19.875 15.8571 19.3993 15.8571 18.8125V8.1875C15.8571 7.6007 15.3774 7.125 14.7857 7.125ZM6.21429 5C4.43908 5 3 6.42709 3 8.1875V18.8125C3 20.5729 4.43909 22 6.21429 22H14.7857C16.5609 22 18 20.5729 18 18.8125V8.1875C18 6.42709 16.5609 5 14.7857 5H6.21429Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<!--end::Svg Icon-->
|
||||
</button>
|
||||
|
||||
|
||||
{{-- Delete --}}
|
||||
@if (Auth::user()->role != 2)
|
||||
<a href="#" data-id="{{ $obj['id'] }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm delete-item">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5 9C5 8.44772 5.44772 8 6 8H18C18.5523 8 19 8.44772 19 9V18C19 19.6569 17.6569 21 16 21H8C6.34315 21 5 19.6569 5 18V9Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M5 5C5 4.44772 5.44772 4 6 4H18C18.5523 4 19 4.44772 19 5V5C19 5.55228 18.5523 6 18 6H6C5.44772 6 5 5.55228 5 5V5Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M9 4C9 3.44772 9.44772 3 10 3H14C14.5523 3 15 3.44772 15 4V4H9V4Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
const baseUrl = "{{ url('document') }}";
|
||||
var datatable;
|
||||
datatable = $("#data-table").DataTable({
|
||||
"info": false,
|
||||
"order": [],
|
||||
"pageLength": 25,
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, 500, 1000],
|
||||
[10, 25, 50, 100, 500, 1000]
|
||||
]
|
||||
});
|
||||
|
||||
// Filter by search
|
||||
const filterSearch = document.querySelector('[table-filter="search"]');
|
||||
filterSearch.addEventListener('keyup', function(e) {
|
||||
datatable.search(e.target.value).draw();
|
||||
});
|
||||
|
||||
// filter by status
|
||||
const filterStatus = document.querySelector('[table-filter="status"]');
|
||||
$(filterStatus).on('change', e => {
|
||||
let value = e.target.value;
|
||||
if (value === 'all') {
|
||||
value = '';
|
||||
}
|
||||
datatable.column(4).search(value).draw();
|
||||
});
|
||||
|
||||
|
||||
// Remove
|
||||
$(document).on('click', '.delete-item', function() {
|
||||
swal.fire({
|
||||
allowOutsideClick: false,
|
||||
text: "Are you sure you would like to Delete?",
|
||||
icon: "warning",
|
||||
buttonsStyling: false,
|
||||
showDenyButton: true,
|
||||
confirmButtonText: "Yes",
|
||||
denyButtonText: 'No',
|
||||
customClass: {
|
||||
confirmButton: "btn btn-primary",
|
||||
denyButton: "btn btn-light-danger"
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
// set up ajax
|
||||
initAjaxSetupToken();
|
||||
|
||||
const ajaxProp = {
|
||||
url: "{{ url('document/delete') }}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
item_id: $(this).data('id')
|
||||
},
|
||||
};
|
||||
|
||||
// const id = $(this).data('id');
|
||||
const id = "{{ $folderView->id }}";
|
||||
|
||||
$.ajax(ajaxProp).done(function(res) {
|
||||
if (res.status) {
|
||||
const url = "{{ url('document/folder') }}/" + id;
|
||||
alertSuccessWithUrl('Notice', "Delete success", url);
|
||||
hideLoading();
|
||||
} else {
|
||||
alertFail('Notice', res.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
logAjaxError(xhr, status, error);
|
||||
alertFail('Notice', error.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const copyButtons = document.querySelectorAll('.copy-button');
|
||||
|
||||
copyButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
const urlToCopy = button.getAttribute('data-url');
|
||||
|
||||
// Copy the URL to the clipboard
|
||||
navigator.clipboard.writeText(urlToCopy).then(() => {
|
||||
alert(
|
||||
'Link copied to clipboard!'
|
||||
); // You can change this to a toast notification
|
||||
}).catch(err => {
|
||||
console.error('Could not copy text: ', err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,451 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<style>
|
||||
.link-container {
|
||||
display: flex;
|
||||
/* Use flexbox for alignment */
|
||||
align-items: center;
|
||||
/* Center items vertically */
|
||||
justify-content: space-between;
|
||||
/* Space between the URL and button */
|
||||
}
|
||||
|
||||
.file-url {
|
||||
flex: 1;
|
||||
/* Allow the URL to take up available space */
|
||||
color: #007bff;
|
||||
/* Link color */
|
||||
text-decoration: none;
|
||||
/* Remove underline */
|
||||
overflow: hidden;
|
||||
/* Hide overflow */
|
||||
white-space: nowrap;
|
||||
/* Prevent text wrapping */
|
||||
text-overflow: ellipsis;
|
||||
/* Add ellipsis for overflow */
|
||||
margin-right: 10px;
|
||||
/* Space between text and button */
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.breadcrumbList', [
|
||||
'title' => 'Document Management',
|
||||
'pageName' => 'Document Management',
|
||||
])
|
||||
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
<div class="card">
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<div class="card-header border-0 pt-6">
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
</div>
|
||||
|
||||
@if (Auth::user()->role != 2)
|
||||
<div class="card-toolbar">
|
||||
<div class="d-flex justify-content-end" style="margin-right: 5px;"
|
||||
data-kt-customer-table-toolbar="base">
|
||||
<a href="{{ url('document/add-folder') }}" class="btn btn-light-primary me-3"
|
||||
id="kt_file_manager_new_folder">New
|
||||
Folder</a>
|
||||
</div>
|
||||
<div class="d-flex justify-content-end" data-kt-customer-table-toolbar="base">
|
||||
<a href="{{ url('document/add') }}" class="btn btn-primary">Add </a>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card-header border-0 pt-5">
|
||||
|
||||
<div class="card-title">
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
<span class="svg-icon svg-icon-1 position-absolute ms-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<rect opacity="0.5" x="17.0365" y="15.1223" width="8.15546" height="2"
|
||||
rx="1" transform="rotate(45 17.0365 15.1223)" fill="currentColor">
|
||||
</rect>
|
||||
<path
|
||||
d="M11 19C6.55556 19 3 15.4444 3 11C3 6.55556 6.55556 3 11 3C15.4444 3 19 6.55556 19 11C19 15.4444 15.4444 19 11 19ZM11 5C7.53333 5 5 7.53333 5 11C5 14.4667 7.53333 17 11 17C14.4667 17 17 14.4667 17 11C17 7.53333 14.4667 5 11 5Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<input type="text" table-filter="search"
|
||||
class="form-control form-control-solid w-250px ps-15" placeholder="Search" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-body py-4">
|
||||
<!--begin::Table-->
|
||||
<table class="table align-middle table-row-dashed fs-6 gy-5" id="data-table">
|
||||
<!--begin::Table head-->
|
||||
<thead>
|
||||
<!--begin::Table row-->
|
||||
<tr class="text-start text-muted fw-bold fs-7 text-uppercase gs-0">
|
||||
<th class="min-w-125px">Name</th>
|
||||
<th class="min-w-125px">Created</th>
|
||||
<th class="text-end min-w-100px">Manage</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="text-gray-600 fw-semibold">
|
||||
|
||||
|
||||
@foreach ($folderView as $obj)
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<span class="svg-icon svg-icon-2x svg-icon-primary me-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3" d="M10 4H21C21.6 4 22 4.4 22 5V7H10V4Z"
|
||||
fill="currentColor"></path>
|
||||
<path
|
||||
d="M9.2 3H3C2.4 3 2 3.4 2 4V19C2 19.6 2.4 20 3 20H21C21.6 20 22 19.6 22 19V7C22 6.4 21.6 6 21 6H12L10.4 3.60001C10.2 3.20001 9.7 3 9.2 3Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<a href="{{ url('document/folder/' . $obj->id) }}"
|
||||
class="text-gray-800 text-hover-primary">
|
||||
{{ $obj->name }}</a>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ Carbon\Carbon::parse($obj['created_at'])->format('d, M Y') }}
|
||||
</td>
|
||||
|
||||
<td class="min-w-100px text-end">
|
||||
|
||||
{{-- Download --}}
|
||||
<a href="{{ url('document/download-folder') . '/' . $obj->id }}"
|
||||
class="btn-download-folder btn btn-sm btn-icon btn-light btn-active-light-primary"
|
||||
type="button" data-bs-toggle="tooltip" aria-label="Coming soon"
|
||||
data-bs-original-title="Coming soon" data-kt-initialized="1">
|
||||
<i class="bi bi-download fs-3"></i>
|
||||
</a>
|
||||
|
||||
{{-- Edit --}}
|
||||
<a href="{{ url('document/edit-folder/' . $obj['id']) }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm me-1">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21.4 8.35303L19.241 10.511L13.485 4.755L15.643 2.59595C16.0248 2.21423 16.5426 1.99988 17.0825 1.99988C17.6224 1.99988 18.1402 2.21423 18.522 2.59595L21.4 5.474C21.7817 5.85581 21.9962 6.37355 21.9962 6.91345C21.9962 7.45335 21.7817 7.97122 21.4 8.35303ZM3.68699 21.932L9.88699 19.865L4.13099 14.109L2.06399 20.309C1.98815 20.5354 1.97703 20.7787 2.03189 21.0111C2.08674 21.2436 2.2054 21.4561 2.37449 21.6248C2.54359 21.7934 2.75641 21.9115 2.989 21.9658C3.22158 22.0201 3.4647 22.0084 3.69099 21.932H3.68699Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M5.574 21.3L3.692 21.928C3.46591 22.0032 3.22334 22.0141 2.99144 21.9594C2.75954 21.9046 2.54744 21.7864 2.3789 21.6179C2.21036 21.4495 2.09202 21.2375 2.03711 21.0056C1.9822 20.7737 1.99289 20.5312 2.06799 20.3051L2.696 18.422L5.574 21.3ZM4.13499 14.105L9.891 19.861L19.245 10.507L13.489 4.75098L4.13499 14.105Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{{-- Delete --}}
|
||||
<a href="#" data-id="{{ $obj['id'] }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm delete-folder-item">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5 9C5 8.44772 5.44772 8 6 8H18C18.5523 8 19 8.44772 19 9V18C19 19.6569 17.6569 21 16 21H8C6.34315 21 5 19.6569 5 18V9Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M5 5C5 4.44772 5.44772 4 6 4H18C18.5523 4 19 4.44772 19 5V5C19 5.55228 18.5523 6 18 6H6C5.44772 6 5 5.55228 5 5V5Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M9 4C9 3.44772 9.44772 3 10 3H14C14.5523 3 15 3.44772 15 4V4H9V4Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
@foreach ($itemView as $obj)
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<a href="#" class="text-gray-800 text-hover-primary">
|
||||
@if (isset($obj['name']) && Str::endsWith($obj['name'], ['.pdf']))
|
||||
<img alt="PDF Icon" class="w-30px me-3"
|
||||
src="{{ url('assets/media/svg/files/pdf.svg') }}">
|
||||
@elseif (isset($obj['name']) && Str::endsWith($obj['name'], ['.doc', '.docx']))
|
||||
<img alt="DOC Icon" class="w-30px me-3"
|
||||
src="{{ url('assets/media/svg/files/doc.svg') }}">
|
||||
@else
|
||||
<span class="svg-icon svg-icon-2x svg-icon-primary me-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M19 22H5C4.4 22 4 21.6 4 21V3C4 2.4 4.4 2 5 2H14L20 8V21C20 21.6 19.6 22 19 22Z"
|
||||
fill="currentColor"></path>
|
||||
<path d="M15 8H20L14 2V7C14 7.6 14.4 8 15 8Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
@endif
|
||||
{{ $obj['name'] }}
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
|
||||
|
||||
<td>
|
||||
{{ Carbon\Carbon::parse($obj['created_at'])->format('d, M Y') }}
|
||||
</td>
|
||||
|
||||
<td class="min-w-100px text-end">
|
||||
|
||||
{{-- Download --}}
|
||||
<a href="{{ env('R2_SCHEMA_URL') . $obj['name'] }}" target="_blank"
|
||||
class="btn btn-sm btn-icon btn-light btn-active-light-primary"
|
||||
type="button" data-bs-toggle="tooltip" aria-label="Coming soon"
|
||||
data-bs-original-title="Coming soon" data-kt-initialized="1">
|
||||
<i class="bi bi-download fs-3"></i>
|
||||
</a>
|
||||
|
||||
{{-- Copy --}}
|
||||
<button type="button" data-action="copy"
|
||||
data-url="{{ env('R2_SCHEMA_URL') . $obj['name'] }}"
|
||||
class="btn btn-sm btn-icon btn-light btn-active-light-primary copy-button">
|
||||
<span class="svg-icon svg-icon-2">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.5"
|
||||
d="M18 2H9C7.34315 2 6 3.34315 6 5H8C8 4.44772 8.44772 4 9 4H18C18.5523 4 19 4.44772 19 5V16C19 16.5523 18.5523 17 18 17V19C19.6569 19 21 17.6569 21 16V5C21 3.34315 19.6569 2 18 2Z"
|
||||
fill="currentColor"></path>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M14.7857 7.125H6.21429C5.62255 7.125 5.14286 7.6007 5.14286 8.1875V18.8125C5.14286 19.3993 5.62255 19.875 6.21429 19.875H14.7857C15.3774 19.875 15.8571 19.3993 15.8571 18.8125V8.1875C15.8571 7.6007 15.3774 7.125 14.7857 7.125ZM6.21429 5C4.43908 5 3 6.42709 3 8.1875V18.8125C3 20.5729 4.43909 22 6.21429 22H14.7857C16.5609 22 18 20.5729 18 18.8125V8.1875C18 6.42709 16.5609 5 14.7857 5H6.21429Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<!--end::Svg Icon-->
|
||||
</button>
|
||||
|
||||
|
||||
{{-- Delete --}}
|
||||
@if (Auth::user()->role != 2)
|
||||
<a href="#" data-id="{{ $obj['id'] }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm delete-item">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5 9C5 8.44772 5.44772 8 6 8H18C18.5523 8 19 8.44772 19 9V18C19 19.6569 17.6569 21 16 21H8C6.34315 21 5 19.6569 5 18V9Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M5 5C5 4.44772 5.44772 4 6 4H18C18.5523 4 19 4.44772 19 5V5C19 5.55228 18.5523 6 18 6H6C5.44772 6 5 5.55228 5 5V5Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M9 4C9 3.44772 9.44772 3 10 3H14C14.5523 3 15 3.44772 15 4V4H9V4Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
const baseUrl = "{{ url('document') }}";
|
||||
var datatable;
|
||||
datatable = $("#data-table").DataTable({
|
||||
"info": false,
|
||||
"order": [],
|
||||
"pageLength": 25,
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, 500, 1000],
|
||||
[10, 25, 50, 100, 500, 1000]
|
||||
]
|
||||
});
|
||||
|
||||
// Filter by search
|
||||
const filterSearch = document.querySelector('[table-filter="search"]');
|
||||
filterSearch.addEventListener('keyup', function(e) {
|
||||
datatable.search(e.target.value).draw();
|
||||
});
|
||||
|
||||
// filter by status
|
||||
const filterStatus = document.querySelector('[table-filter="status"]');
|
||||
$(filterStatus).on('change', e => {
|
||||
let value = e.target.value;
|
||||
if (value === 'all') {
|
||||
value = '';
|
||||
}
|
||||
datatable.column(4).search(value).draw();
|
||||
});
|
||||
|
||||
|
||||
// Remove
|
||||
$(document).on('click', '.delete-item', function() {
|
||||
swal.fire({
|
||||
allowOutsideClick: false,
|
||||
text: "Are you sure you would like to Delete?",
|
||||
icon: "warning",
|
||||
buttonsStyling: false,
|
||||
showDenyButton: true,
|
||||
confirmButtonText: "Yes",
|
||||
denyButtonText: 'No',
|
||||
customClass: {
|
||||
confirmButton: "btn btn-primary",
|
||||
denyButton: "btn btn-light-danger"
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
// set up ajax
|
||||
initAjaxSetupToken();
|
||||
|
||||
const ajaxProp = {
|
||||
url: "{{ url('document/delete') }}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
item_id: $(this).data('id')
|
||||
},
|
||||
};
|
||||
|
||||
$.ajax(ajaxProp).done(function(res) {
|
||||
if (res.status) {
|
||||
const url = "{{ url('document') }}";
|
||||
alertSuccessWithUrl('Notice', "Delete success", url);
|
||||
hideLoading();
|
||||
} else {
|
||||
alertFail('Notice', res.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
logAjaxError(xhr, status, error);
|
||||
alertFail('Notice', error.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const copyButtons = document.querySelectorAll('.copy-button');
|
||||
|
||||
copyButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
const urlToCopy = button.getAttribute('data-url');
|
||||
|
||||
// Copy the URL to the clipboard
|
||||
navigator.clipboard.writeText(urlToCopy).then(() => {
|
||||
alert(
|
||||
'Link copied to clipboard!'
|
||||
); // You can change this to a toast notification
|
||||
}).catch(err => {
|
||||
console.error('Could not copy text: ', err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Delete folder
|
||||
$(document).on('click', '.delete-folder-item', function() {
|
||||
swal.fire({
|
||||
allowOutsideClick: false,
|
||||
text: "Are you sure you would like to Delete?",
|
||||
icon: "warning",
|
||||
buttonsStyling: false,
|
||||
showDenyButton: true,
|
||||
confirmButtonText: "Yes",
|
||||
denyButtonText: 'No',
|
||||
customClass: {
|
||||
confirmButton: "btn btn-primary",
|
||||
denyButton: "btn btn-light-danger"
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
// set up ajax
|
||||
initAjaxSetupToken();
|
||||
|
||||
const ajaxProp = {
|
||||
url: "{{ url('document/delete-folder') }}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
item_id: $(this).data('id')
|
||||
},
|
||||
};
|
||||
|
||||
$.ajax(ajaxProp).done(function(res) {
|
||||
if (res.status) {
|
||||
const url = "{{ url('document') }}";
|
||||
alertSuccessWithUrl('Notice', "Delete success", url);
|
||||
hideLoading();
|
||||
} else {
|
||||
alertFail('Notice', res.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
logAjaxError(xhr, status, error);
|
||||
alertFail('Notice', error.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,121 @@
|
||||
@extends('layouts.loginTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<form class="form w-100" novalidate="novalidate" id="frm-forgot-password" method="post"
|
||||
action="{{ url('post-forgot-password') }}">
|
||||
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
<!--begin::Heading-->
|
||||
<div class="text-center mb-11">
|
||||
<!--begin::Title-->
|
||||
<h1 class="text-dark fw-bolder mb-3">Forgot Password</h1>
|
||||
<!--end::Title-->
|
||||
</div>
|
||||
<!--begin::Heading-->
|
||||
|
||||
|
||||
<!--begin::Input group=-->
|
||||
<div class="fv-row mb-8">
|
||||
<!--begin::Email-->
|
||||
<input type="email" placeholder="Email" name="email" autocomplete="off"
|
||||
class="form-control bg-transparent" />
|
||||
<!--end::Email-->
|
||||
</div>
|
||||
|
||||
<!--end::Input group=-->
|
||||
<!--begin::Wrapper-->
|
||||
<div class="d-flex flex-stack flex-wrap gap-3 fs-base fw-semibold mb-8">
|
||||
<div></div>
|
||||
<!--begin::Link-->
|
||||
<a href="{{ url('login') }}" class="link-primary">Login ?</a>
|
||||
<!--end::Link-->
|
||||
</div>
|
||||
<!--end::Wrapper-->
|
||||
|
||||
<!--begin::Submit button-->
|
||||
<div class="d-grid mb-10">
|
||||
<button type="button" id="btn-submit" class="btn btn-primary">
|
||||
<!--begin::Indicator label-->
|
||||
<span class="indicator-label">Submit</span>
|
||||
<!--end::Indicator label-->
|
||||
<!--begin::Indicator progress-->
|
||||
<span class="indicator-progress">Please wait...
|
||||
<span class="spinner-border spinner-border-sm align-middle ms-2"></span></span>
|
||||
<!--end::Indicator progress-->
|
||||
</button>
|
||||
</div>
|
||||
<!--end::Submit button-->
|
||||
|
||||
</form>
|
||||
|
||||
@stop
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
|
||||
$(document).on("click", "#btn-submit", function(e) {
|
||||
|
||||
// handle bomb click
|
||||
e.preventDefault();
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
formSubmit()
|
||||
})
|
||||
|
||||
var inputPassword = document.getElementById("input-password");
|
||||
|
||||
// Execute a function when the user presses a key on the keyboard
|
||||
inputPassword.addEventListener("keypress", function(event) {
|
||||
// If the user presses the "Enter" key on the keyboard
|
||||
if (event.key === "Enter") {
|
||||
// Cancel the default action, if needed
|
||||
event.preventDefault();
|
||||
alertLoading("Loading")
|
||||
// Trigger the button element with a click
|
||||
document.getElementById("btn-submit").click();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
function formSubmit() {
|
||||
// form data
|
||||
const form = $('#frm-forgot-password')[0];
|
||||
const formData = new FormData(form);
|
||||
|
||||
// set up ajax
|
||||
initAjaxSetupToken();
|
||||
|
||||
const ajaxProp = {
|
||||
url: "{{ url('post-forgot-password') }}",
|
||||
dataType: 'json',
|
||||
method: 'post',
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
};
|
||||
|
||||
$.ajax(ajaxProp).done(function(res) {
|
||||
if (isAjaxStatusSuccess(res.status)) {
|
||||
alertSuccess('Notice', 'Please check your email address')
|
||||
window.location.href = '{{ url('') }}';
|
||||
hideLoading();
|
||||
} else {
|
||||
alertFail('Notice', res.message ?? "Forgot password unsuccessfully");
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
logAjaxError(xhr, status, error);
|
||||
alertFail('Notice', error.message ?? "Forgot password unsuccessfully");
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,367 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<style>
|
||||
#progressBar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
border-radius: 5px;
|
||||
margin-top: 10px;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.progress-bar::-webkit-progress-value {
|
||||
background-color: #4CAF50;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
margin-top: 10px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'Image Add',
|
||||
'pageName' => 'Add',
|
||||
'pageParent' => 'Image Management',
|
||||
'pageParentLink' => url('image'),
|
||||
])
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
|
||||
|
||||
<form id="frmAdd" class="form d-flex flex-column flex-lg-row" method="post"
|
||||
enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<div class="mb-10">
|
||||
<label class="form-label required">File Image</label>
|
||||
|
||||
<input class="fileInput file-input" type="file" id="fileInput" name="fileInput"
|
||||
accept=".jpg, .bmp, .jpeg, .png" multiple>
|
||||
|
||||
<progress id="progressBar" class="progress-bar" value="0"
|
||||
max="100"></progress>
|
||||
<div id="progressText" class="progress-text">0%</div>
|
||||
|
||||
<div class="text-muted fs-7">Allowed Types .jpg, .bmp, .jpeg, .png</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('image') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button type="button" id="btn_submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script>
|
||||
const baseApiUrl = "{{ env('API_URL') }}";
|
||||
|
||||
|
||||
$(document).on("click", "#btn_submit", async function(e) {
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
await uploadFile();
|
||||
|
||||
});
|
||||
|
||||
|
||||
// Step 1
|
||||
async function uploadFile() {
|
||||
const fileInput = document.getElementById("fileInput");
|
||||
const progressBar = document.getElementById("progressBar");
|
||||
const progressText = document.getElementById("progressText");
|
||||
|
||||
if (!fileInput || fileInput.files.length === 0) {
|
||||
alertFail("Notice", "Please select one or more files.");
|
||||
hideLoading();
|
||||
return;
|
||||
}
|
||||
|
||||
const files = Array.from(fileInput.files); // Get all selected files
|
||||
$("#progressBar").show();
|
||||
|
||||
let totalSize = files.reduce((sum, file) => sum + file.size, 0);
|
||||
let totalUploadedSize = 0;
|
||||
|
||||
// Upload all files sequentially
|
||||
for (const file of files) {
|
||||
await uploadSingleFile(file, progressBar, progressText, totalSize, (fileUploadedSize) => {
|
||||
totalUploadedSize += fileUploadedSize;
|
||||
const overallPercent = Math.floor((totalUploadedSize / totalSize) * 100);
|
||||
animateProgress(progressBar, progressText, overallPercent);
|
||||
});
|
||||
}
|
||||
|
||||
const folderId = "{{ $folderIdView }}";
|
||||
console.log('folderId', folderId);
|
||||
let redirectUrl = "{{ url('image') }}"
|
||||
if (folderId) {
|
||||
redirectUrl = `${redirectUrl}/folder/${folderId}`;
|
||||
}
|
||||
alertSuccessWithUrl("Notice", "All files uploaded successfully", redirectUrl);
|
||||
}
|
||||
|
||||
async function uploadSingleFile(file, progressBar, progressText, totalSize, updateOverallProgress) {
|
||||
const uploadId = await initiateMultipartUpload(file.name);
|
||||
const partSize = 500 * 1024 * 1024; // 500 MB per part
|
||||
const parts = [];
|
||||
let uploadedSize = 0;
|
||||
|
||||
const uploadPromises = Array.from({
|
||||
length: Math.ceil(file.size / partSize)
|
||||
},
|
||||
(_, index) => {
|
||||
const partNumber = index + 1;
|
||||
const chunk = file.slice(index * partSize, (index + 1) * partSize);
|
||||
|
||||
return (async () => {
|
||||
const presignedUrl = await getPresignedUrl(uploadId, partNumber, file.name);
|
||||
const etag = await uploadPartToS3(presignedUrl, chunk);
|
||||
|
||||
parts.push({
|
||||
PartNumber: partNumber,
|
||||
ETag: etag
|
||||
});
|
||||
|
||||
uploadedSize += chunk.size;
|
||||
updateOverallProgress(chunk.size); // Update the overall progress
|
||||
})();
|
||||
}
|
||||
);
|
||||
|
||||
await Promise.all(uploadPromises);
|
||||
await completeMultipartUpload(uploadId, parts, file.name);
|
||||
await saveFileNameToDB(file.name);
|
||||
}
|
||||
|
||||
// Step 2
|
||||
async function initiateMultipartUpload(fileName) {
|
||||
const urlUploadImage = `${baseApiUrl}/initiate-multipart-upload`;
|
||||
const response = await fetch(
|
||||
urlUploadImage, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
fileName
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
const {
|
||||
uploadId
|
||||
} = await response.json();
|
||||
|
||||
return uploadId;
|
||||
}
|
||||
|
||||
// Step 3
|
||||
async function getPresignedUrl(uploadId, partNumber, fileName) {
|
||||
|
||||
const urlPresigned = `${baseApiUrl}/get-presigned-url`
|
||||
const response = await fetch(
|
||||
urlPresigned, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
uploadId,
|
||||
partNumber,
|
||||
fileName
|
||||
}),
|
||||
}
|
||||
);
|
||||
const {
|
||||
url
|
||||
} = await response.json();
|
||||
return url;
|
||||
}
|
||||
|
||||
// Step 4
|
||||
async function uploadPartToS3(url, chunk) {
|
||||
const response = await fetch(url, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/octet-stream",
|
||||
},
|
||||
body: chunk,
|
||||
});
|
||||
if (!response.ok) {
|
||||
alertFail("Notice", "Failed to upload part")
|
||||
hideLoading();
|
||||
//throw new Error("Failed to upload part");
|
||||
}
|
||||
|
||||
const etag = `${response.headers.get("ETag")}`.replace(/"/g, "");
|
||||
|
||||
if (!etag) {
|
||||
throw new Error("Failed to retrieve ETag from the response.");
|
||||
}
|
||||
|
||||
return etag;
|
||||
}
|
||||
|
||||
// Step 5
|
||||
async function completeMultipartUpload(uploadId, parts, fileName) {
|
||||
const urlUploadComplete = `${baseApiUrl}/complete-multipart-upload`;
|
||||
const response = await fetch(urlUploadComplete, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
uploadId,
|
||||
parts,
|
||||
fileName
|
||||
}),
|
||||
});
|
||||
if (response.ok) {
|
||||
//window.location.href = "{{ url('image') }}";
|
||||
} else {
|
||||
alertFail("Notice", "Failed to upload part");
|
||||
hideLoading();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Smoothly animates the progress bar and percentage text.
|
||||
*/
|
||||
async function animateProgress(progressBar, progressText, targetPercent) {
|
||||
const currentPercent = parseInt(progressBar.value) || 0;
|
||||
// Increment the percentage smoothly
|
||||
for (let percent = currentPercent + 1; percent <= targetPercent; percent++) {
|
||||
progressBar.value = percent;
|
||||
progressText.textContent = `${percent}%`;
|
||||
|
||||
// Add a small delay to make the increment visible (10ms delay)
|
||||
await new Promise((resolve) => setTimeout(resolve, 10));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the uploaded file name to the server using AJAX.
|
||||
*/
|
||||
function saveFileNameToDB(fileName) {
|
||||
initAjaxSetupToken();
|
||||
|
||||
const folderId = "{{ $folderIdView }}";
|
||||
const url = "{{ url('') }}";
|
||||
|
||||
return $.ajax({
|
||||
url: `${url}/image/insert`,
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({
|
||||
fileName,
|
||||
folderId
|
||||
}),
|
||||
success: (response) => {
|
||||
console.log('File name saved:', response);
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Error saving file name:', err);
|
||||
alertFail("Notice", "There was an error saving the file name.");
|
||||
hideLoading();
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
$('.file-input').fileuploader({
|
||||
extensions: ['jpg', 'bmp', 'jpeg', 'png'],
|
||||
limit: null,
|
||||
fileMaxSize: null,
|
||||
changeInput: '<div class="fileuploader-input">' +
|
||||
'<div class="fileuploader-input-inner">' +
|
||||
'<p><i class="fileuploader-icon-main"></i></p>' +
|
||||
'<h6>Drag and drop files here</h6>' +
|
||||
'<p>or</p>' +
|
||||
'<br>' +
|
||||
'<button type="button" class="fileuploader-input-button"><span>${captions.button}</span></button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
theme: 'dragdrop',
|
||||
});
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,95 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'Image Create Folder',
|
||||
'pageName' => 'Create folder',
|
||||
'pageParent' => 'Image Management',
|
||||
'pageParentLink' => url('image'),
|
||||
])
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
<form id="frmAdd" action="{{ url('image/insert-folder') }}" class="form d-flex flex-column flex-lg-row"
|
||||
method="post" enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Name</label>
|
||||
<input type="text" name="name" class="form-control mb-2 col-6"
|
||||
value="{{ old('name') }}" />
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('image') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script></script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,96 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'Image Edit Folder',
|
||||
'pageName' => 'Edit folder',
|
||||
'pageParent' => 'Image Management',
|
||||
'pageParentLink' => url('image'),
|
||||
])
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
<form id="frmAdd" action="{{ url('image/update-folder') }}" class="form d-flex flex-column flex-lg-row"
|
||||
method="post" enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="id" value="{{ $idView }}">
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Name</label>
|
||||
<input type="text" name="name" class="form-control mb-2 col-6"
|
||||
value="{{ $itemView->name }}" />
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('image') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script></script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,316 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<style>
|
||||
.link-container {
|
||||
display: flex;
|
||||
/* Use flexbox for alignment */
|
||||
align-items: center;
|
||||
/* Center items vertically */
|
||||
justify-content: space-between;
|
||||
/* Space between the URL and button */
|
||||
}
|
||||
|
||||
.file-url {
|
||||
flex: 1;
|
||||
/* Allow the URL to take up available space */
|
||||
color: #007bff;
|
||||
/* Link color */
|
||||
text-decoration: none;
|
||||
/* Remove underline */
|
||||
overflow: hidden;
|
||||
/* Hide overflow */
|
||||
white-space: nowrap;
|
||||
/* Prevent text wrapping */
|
||||
text-overflow: ellipsis;
|
||||
/* Add ellipsis for overflow */
|
||||
margin-right: 10px;
|
||||
/* Space between text and button */
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.breadcrumbList', [
|
||||
'title' => 'Image Management Folder ' . $folderView->name,
|
||||
'pageName' => 'Image Management',
|
||||
])
|
||||
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
<div class="card">
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<div class="card-header border-0 pt-6">
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
</div>
|
||||
|
||||
@if (Auth::user()->role != 2)
|
||||
<div class="card-toolbar">
|
||||
<div class="d-flex justify-content-end" data-kt-customer-table-toolbar="base">
|
||||
<a href="{{ url('image/add/' . $folderView->id) }}" class="btn btn-primary">Add
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card-header border-0 pt-5">
|
||||
|
||||
<div class="card-title">
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
<span class="svg-icon svg-icon-1 position-absolute ms-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<rect opacity="0.5" x="17.0365" y="15.1223" width="8.15546" height="2"
|
||||
rx="1" transform="rotate(45 17.0365 15.1223)" fill="currentColor">
|
||||
</rect>
|
||||
<path
|
||||
d="M11 19C6.55556 19 3 15.4444 3 11C3 6.55556 6.55556 3 11 3C15.4444 3 19 6.55556 19 11C19 15.4444 15.4444 19 11 19ZM11 5C7.53333 5 5 7.53333 5 11C5 14.4667 7.53333 17 11 17C14.4667 17 17 14.4667 17 11C17 7.53333 14.4667 5 11 5Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<input type="text" table-filter="search"
|
||||
class="form-control form-control-solid w-250px ps-15" placeholder="Search" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-body py-4">
|
||||
<!--begin::Table-->
|
||||
<table class="table align-middle table-row-dashed fs-6 gy-5" id="data-table">
|
||||
<!--begin::Table head-->
|
||||
<thead>
|
||||
<!--begin::Table row-->
|
||||
<tr class="text-start text-muted fw-bold fs-7 text-uppercase gs-0">
|
||||
<th class="min-w-125px">Name</th>
|
||||
<th class="min-w-125px">Created</th>
|
||||
<th class="text-end min-w-100px">Manage</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="text-gray-600 fw-semibold">
|
||||
|
||||
@foreach ($itemView as $obj)
|
||||
<tr>
|
||||
<td class="d-flex align-items-center">
|
||||
<!--begin:: Avatar -->
|
||||
<div class="symbol symbol-100px overflow-hidden me-3">
|
||||
<a class="show-image-preview"
|
||||
href="{{ env('R2_SCHEMA_URL') . $obj['name'] }}">
|
||||
<div class="symbol-label">
|
||||
<img src="{{ env('R2_SCHEMA_URL') . $obj['name'] }}"
|
||||
alt="Emma Smith" class="w-100">
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="d-flex flex-column">
|
||||
<a href="#"
|
||||
class="text-gray-800 text-hover-primary mb-1">{{ $obj['name'] }}</a>
|
||||
|
||||
</div>
|
||||
<!--begin::User details-->
|
||||
</td>
|
||||
|
||||
|
||||
<td>
|
||||
{{ Carbon\Carbon::parse($obj['created_at'])->format('d, M Y') }}
|
||||
</td>
|
||||
|
||||
<td class="min-w-100px text-end">
|
||||
|
||||
{{-- Download --}}
|
||||
<a href="{{ env('R2_SCHEMA_URL') . $obj['name'] }}" target="_blank"
|
||||
class="btn btn-sm btn-icon btn-light btn-active-light-primary"
|
||||
type="button" data-bs-toggle="tooltip" aria-label="Coming soon"
|
||||
data-bs-original-title="Coming soon" data-kt-initialized="1">
|
||||
<i class="bi bi-download fs-3"></i>
|
||||
</a>
|
||||
|
||||
{{-- Copy --}}
|
||||
<button type="button" data-action="copy"
|
||||
data-url="{{ env('R2_SCHEMA_URL') . $obj['name'] }}"
|
||||
class="btn btn-sm btn-icon btn-light btn-active-light-primary copy-button">
|
||||
<span class="svg-icon svg-icon-2">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.5"
|
||||
d="M18 2H9C7.34315 2 6 3.34315 6 5H8C8 4.44772 8.44772 4 9 4H18C18.5523 4 19 4.44772 19 5V16C19 16.5523 18.5523 17 18 17V19C19.6569 19 21 17.6569 21 16V5C21 3.34315 19.6569 2 18 2Z"
|
||||
fill="currentColor"></path>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M14.7857 7.125H6.21429C5.62255 7.125 5.14286 7.6007 5.14286 8.1875V18.8125C5.14286 19.3993 5.62255 19.875 6.21429 19.875H14.7857C15.3774 19.875 15.8571 19.3993 15.8571 18.8125V8.1875C15.8571 7.6007 15.3774 7.125 14.7857 7.125ZM6.21429 5C4.43908 5 3 6.42709 3 8.1875V18.8125C3 20.5729 4.43909 22 6.21429 22H14.7857C16.5609 22 18 20.5729 18 18.8125V8.1875C18 6.42709 16.5609 5 14.7857 5H6.21429Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<!--end::Svg Icon-->
|
||||
</button>
|
||||
|
||||
|
||||
{{-- Delete --}}
|
||||
@if (Auth::user()->role != 2)
|
||||
<a href="#" data-id="{{ $obj['id'] }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm delete-item">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5 9C5 8.44772 5.44772 8 6 8H18C18.5523 8 19 8.44772 19 9V18C19 19.6569 17.6569 21 16 21H8C6.34315 21 5 19.6569 5 18V9Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M5 5C5 4.44772 5.44772 4 6 4H18C18.5523 4 19 4.44772 19 5V5C19 5.55228 18.5523 6 18 6H6C5.44772 6 5 5.55228 5 5V5Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M9 4C9 3.44772 9.44772 3 10 3H14C14.5523 3 15 3.44772 15 4V4H9V4Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
const baseUrl = "{{ url('image') }}";
|
||||
var datatable;
|
||||
datatable = $("#data-table").DataTable({
|
||||
"info": false,
|
||||
"order": [],
|
||||
"pageLength": 25,
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, 500, 1000],
|
||||
[10, 25, 50, 100, 500, 1000]
|
||||
]
|
||||
});
|
||||
|
||||
// Filter by search
|
||||
const filterSearch = document.querySelector('[table-filter="search"]');
|
||||
filterSearch.addEventListener('keyup', function(e) {
|
||||
datatable.search(e.target.value).draw();
|
||||
});
|
||||
|
||||
// filter by status
|
||||
const filterStatus = document.querySelector('[table-filter="status"]');
|
||||
$(filterStatus).on('change', e => {
|
||||
let value = e.target.value;
|
||||
if (value === 'all') {
|
||||
value = '';
|
||||
}
|
||||
datatable.column(4).search(value).draw();
|
||||
});
|
||||
|
||||
|
||||
// Remove
|
||||
$(document).on('click', '.delete-item', function() {
|
||||
swal.fire({
|
||||
allowOutsideClick: false,
|
||||
text: "Are you sure you would like to Delete?",
|
||||
icon: "warning",
|
||||
buttonsStyling: false,
|
||||
showDenyButton: true,
|
||||
confirmButtonText: "Yes",
|
||||
denyButtonText: 'No',
|
||||
customClass: {
|
||||
confirmButton: "btn btn-primary",
|
||||
denyButton: "btn btn-light-danger"
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
// set up ajax
|
||||
initAjaxSetupToken();
|
||||
|
||||
const ajaxProp = {
|
||||
url: "{{ url('image/delete') }}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
item_id: $(this).data('id')
|
||||
},
|
||||
};
|
||||
|
||||
//const id = $(this).data('id');
|
||||
const id = "{{ $folderView->id }}";
|
||||
|
||||
$.ajax(ajaxProp).done(function(res) {
|
||||
if (res.status) {
|
||||
const url = "{{ url('image/folder') }}/" + id;
|
||||
alertSuccessWithUrl('Notice', "Delete success", url);
|
||||
hideLoading();
|
||||
} else {
|
||||
alertFail('Notice', res.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
logAjaxError(xhr, status, error);
|
||||
alertFail('Notice', error.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const copyButtons = document.querySelectorAll('.copy-button');
|
||||
|
||||
copyButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
const urlToCopy = button.getAttribute('data-url');
|
||||
|
||||
// Copy the URL to the clipboard
|
||||
navigator.clipboard.writeText(urlToCopy).then(() => {
|
||||
alert(
|
||||
'Link copied to clipboard!'
|
||||
); // You can change this to a toast notification
|
||||
}).catch(err => {
|
||||
console.error('Could not copy text: ', err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,449 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<style>
|
||||
.link-container {
|
||||
display: flex;
|
||||
/* Use flexbox for alignment */
|
||||
align-items: center;
|
||||
/* Center items vertically */
|
||||
justify-content: space-between;
|
||||
/* Space between the URL and button */
|
||||
}
|
||||
|
||||
.file-url {
|
||||
flex: 1;
|
||||
/* Allow the URL to take up available space */
|
||||
color: #007bff;
|
||||
/* Link color */
|
||||
text-decoration: none;
|
||||
/* Remove underline */
|
||||
overflow: hidden;
|
||||
/* Hide overflow */
|
||||
white-space: nowrap;
|
||||
/* Prevent text wrapping */
|
||||
text-overflow: ellipsis;
|
||||
/* Add ellipsis for overflow */
|
||||
margin-right: 10px;
|
||||
/* Space between text and button */
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.breadcrumbList', [
|
||||
'title' => 'Image Management',
|
||||
'pageName' => 'Image Management',
|
||||
])
|
||||
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
<div class="card">
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<div class="card-header border-0 pt-6">
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
</div>
|
||||
|
||||
@if (Auth::user()->role != 2)
|
||||
<div class="card-toolbar">
|
||||
|
||||
<div class="d-flex justify-content-end" style="margin-right: 5px;"
|
||||
data-kt-customer-table-toolbar="base">
|
||||
<a href="{{ url('image/add-folder') }}" class="btn btn-light-primary me-3"
|
||||
id="kt_file_manager_new_folder">New
|
||||
Folder</a>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end" data-kt-customer-table-toolbar="base">
|
||||
<a href="{{ url('image/add') }}" class="btn btn-primary">Add </a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card-header border-0 pt-5">
|
||||
|
||||
<div class="card-title">
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
<span class="svg-icon svg-icon-1 position-absolute ms-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<rect opacity="0.5" x="17.0365" y="15.1223" width="8.15546" height="2"
|
||||
rx="1" transform="rotate(45 17.0365 15.1223)" fill="currentColor">
|
||||
</rect>
|
||||
<path
|
||||
d="M11 19C6.55556 19 3 15.4444 3 11C3 6.55556 6.55556 3 11 3C15.4444 3 19 6.55556 19 11C19 15.4444 15.4444 19 11 19ZM11 5C7.53333 5 5 7.53333 5 11C5 14.4667 7.53333 17 11 17C14.4667 17 17 14.4667 17 11C17 7.53333 14.4667 5 11 5Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<input type="text" table-filter="search"
|
||||
class="form-control form-control-solid w-250px ps-15" placeholder="Search" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-body py-4">
|
||||
<!--begin::Table-->
|
||||
<table class="table align-middle table-row-dashed fs-6 gy-5" id="data-table">
|
||||
<!--begin::Table head-->
|
||||
<thead>
|
||||
<!--begin::Table row-->
|
||||
<tr class="text-start text-muted fw-bold fs-7 text-uppercase gs-0">
|
||||
<th class="min-w-125px">Name</th>
|
||||
<th class="min-w-125px">Created</th>
|
||||
<th class="text-end min-w-100px">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="text-gray-600 fw-semibold">
|
||||
|
||||
@foreach ($folderView as $obj)
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<span class="svg-icon svg-icon-2x svg-icon-primary me-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3" d="M10 4H21C21.6 4 22 4.4 22 5V7H10V4Z"
|
||||
fill="currentColor"></path>
|
||||
<path
|
||||
d="M9.2 3H3C2.4 3 2 3.4 2 4V19C2 19.6 2.4 20 3 20H21C21.6 20 22 19.6 22 19V7C22 6.4 21.6 6 21 6H12L10.4 3.60001C10.2 3.20001 9.7 3 9.2 3Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<a href="{{ url('image/folder/' . $obj->id) }}"
|
||||
class="text-gray-800 text-hover-primary">
|
||||
{{ $obj->name }}</a>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ Carbon\Carbon::parse($obj['created_at'])->format('d, M Y') }}
|
||||
</td>
|
||||
|
||||
<td class="min-w-100px text-end">
|
||||
|
||||
{{-- Download --}}
|
||||
<a href="{{ url('image/download-folder') . '/' . $obj->id }}"
|
||||
class="btn-download-folder btn btn-sm btn-icon btn-light btn-active-light-primary"
|
||||
type="button" data-bs-toggle="tooltip" aria-label="Coming soon"
|
||||
data-bs-original-title="Coming soon" data-kt-initialized="1">
|
||||
<i class="bi bi-download fs-3"></i>
|
||||
</a>
|
||||
|
||||
{{-- Edit --}}
|
||||
<a href="{{ url('image/edit-folder/' . $obj['id']) }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm me-1">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21.4 8.35303L19.241 10.511L13.485 4.755L15.643 2.59595C16.0248 2.21423 16.5426 1.99988 17.0825 1.99988C17.6224 1.99988 18.1402 2.21423 18.522 2.59595L21.4 5.474C21.7817 5.85581 21.9962 6.37355 21.9962 6.91345C21.9962 7.45335 21.7817 7.97122 21.4 8.35303ZM3.68699 21.932L9.88699 19.865L4.13099 14.109L2.06399 20.309C1.98815 20.5354 1.97703 20.7787 2.03189 21.0111C2.08674 21.2436 2.2054 21.4561 2.37449 21.6248C2.54359 21.7934 2.75641 21.9115 2.989 21.9658C3.22158 22.0201 3.4647 22.0084 3.69099 21.932H3.68699Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M5.574 21.3L3.692 21.928C3.46591 22.0032 3.22334 22.0141 2.99144 21.9594C2.75954 21.9046 2.54744 21.7864 2.3789 21.6179C2.21036 21.4495 2.09202 21.2375 2.03711 21.0056C1.9822 20.7737 1.99289 20.5312 2.06799 20.3051L2.696 18.422L5.574 21.3ZM4.13499 14.105L9.891 19.861L19.245 10.507L13.489 4.75098L4.13499 14.105Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{{-- Delete --}}
|
||||
<a href="#" data-id="{{ $obj['id'] }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm delete-folder-item">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5 9C5 8.44772 5.44772 8 6 8H18C18.5523 8 19 8.44772 19 9V18C19 19.6569 17.6569 21 16 21H8C6.34315 21 5 19.6569 5 18V9Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M5 5C5 4.44772 5.44772 4 6 4H18C18.5523 4 19 4.44772 19 5V5C19 5.55228 18.5523 6 18 6H6C5.44772 6 5 5.55228 5 5V5Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M9 4C9 3.44772 9.44772 3 10 3H14C14.5523 3 15 3.44772 15 4V4H9V4Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
|
||||
@foreach ($itemView as $obj)
|
||||
<tr>
|
||||
|
||||
<td class="d-flex align-items-center">
|
||||
<!--begin:: Avatar -->
|
||||
<div class="symbol symbol-100px overflow-hidden me-3">
|
||||
<a class="show-image-preview"
|
||||
href="{{ env('R2_SCHEMA_URL') . $obj['name'] }}">
|
||||
<div class="symbol-label">
|
||||
<img src="{{ env('R2_SCHEMA_URL') . $obj['name'] }}"
|
||||
alt="Emma Smith" class="w-100">
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="d-flex flex-column">
|
||||
<a href="#"
|
||||
class="text-gray-800 text-hover-primary mb-1">{{ $obj['name'] }}</a>
|
||||
|
||||
</div>
|
||||
<!--begin::User details-->
|
||||
</td>
|
||||
|
||||
|
||||
<td>
|
||||
{{ Carbon\Carbon::parse($obj['created_at'])->format('d, M Y') }}
|
||||
</td>
|
||||
|
||||
|
||||
<td class="min-w-100px text-end">
|
||||
|
||||
{{-- Download --}}
|
||||
<a download="{{ env('R2_SCHEMA_URL') . $obj['name'] }}"
|
||||
href="{{ env('R2_SCHEMA_URL') . $obj['name'] }}" target="_blank"
|
||||
class="btn btn-sm btn-icon btn-light btn-active-light-primary"
|
||||
type="button" data-bs-toggle="tooltip" aria-label="Coming soon"
|
||||
data-bs-original-title="Coming soon" data-kt-initialized="1">
|
||||
<i class="bi bi-download fs-3"></i>
|
||||
</a>
|
||||
|
||||
{{-- Copy --}}
|
||||
<button type="button" data-action="copy"
|
||||
data-url="{{ env('R2_SCHEMA_URL') . $obj['name'] }}"
|
||||
class="btn btn-sm btn-icon btn-light btn-active-light-primary copy-button">
|
||||
<span class="svg-icon svg-icon-2">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.5"
|
||||
d="M18 2H9C7.34315 2 6 3.34315 6 5H8C8 4.44772 8.44772 4 9 4H18C18.5523 4 19 4.44772 19 5V16C19 16.5523 18.5523 17 18 17V19C19.6569 19 21 17.6569 21 16V5C21 3.34315 19.6569 2 18 2Z"
|
||||
fill="currentColor"></path>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M14.7857 7.125H6.21429C5.62255 7.125 5.14286 7.6007 5.14286 8.1875V18.8125C5.14286 19.3993 5.62255 19.875 6.21429 19.875H14.7857C15.3774 19.875 15.8571 19.3993 15.8571 18.8125V8.1875C15.8571 7.6007 15.3774 7.125 14.7857 7.125ZM6.21429 5C4.43908 5 3 6.42709 3 8.1875V18.8125C3 20.5729 4.43909 22 6.21429 22H14.7857C16.5609 22 18 20.5729 18 18.8125V8.1875C18 6.42709 16.5609 5 14.7857 5H6.21429Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<!--end::Svg Icon-->
|
||||
</button>
|
||||
|
||||
|
||||
{{-- Delete --}}
|
||||
@if (Auth::user()->role != 2)
|
||||
<a href="#" data-id="{{ $obj['id'] }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm delete-item">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5 9C5 8.44772 5.44772 8 6 8H18C18.5523 8 19 8.44772 19 9V18C19 19.6569 17.6569 21 16 21H8C6.34315 21 5 19.6569 5 18V9Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M5 5C5 4.44772 5.44772 4 6 4H18C18.5523 4 19 4.44772 19 5V5C19 5.55228 18.5523 6 18 6H6C5.44772 6 5 5.55228 5 5V5Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M9 4C9 3.44772 9.44772 3 10 3H14C14.5523 3 15 3.44772 15 4V4H9V4Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
const baseUrl = "{{ url('image') }}";
|
||||
var datatable;
|
||||
datatable = $("#data-table").DataTable({
|
||||
"info": false,
|
||||
"order": [],
|
||||
"pageLength": 25,
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, 500, 1000],
|
||||
[10, 25, 50, 100, 500, 1000]
|
||||
]
|
||||
});
|
||||
|
||||
// Filter by search
|
||||
const filterSearch = document.querySelector('[table-filter="search"]');
|
||||
filterSearch.addEventListener('keyup', function(e) {
|
||||
datatable.search(e.target.value).draw();
|
||||
});
|
||||
|
||||
// filter by status
|
||||
const filterStatus = document.querySelector('[table-filter="status"]');
|
||||
$(filterStatus).on('change', e => {
|
||||
let value = e.target.value;
|
||||
if (value === 'all') {
|
||||
value = '';
|
||||
}
|
||||
datatable.column(4).search(value).draw();
|
||||
});
|
||||
|
||||
|
||||
// Remove
|
||||
$(document).on('click', '.delete-item', function() {
|
||||
swal.fire({
|
||||
allowOutsideClick: false,
|
||||
text: "Are you sure you would like to Delete?",
|
||||
icon: "warning",
|
||||
buttonsStyling: false,
|
||||
showDenyButton: true,
|
||||
confirmButtonText: "Yes",
|
||||
denyButtonText: 'No',
|
||||
customClass: {
|
||||
confirmButton: "btn btn-primary",
|
||||
denyButton: "btn btn-light-danger"
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
// set up ajax
|
||||
initAjaxSetupToken();
|
||||
|
||||
const ajaxProp = {
|
||||
url: "{{ url('image/delete') }}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
item_id: $(this).data('id')
|
||||
},
|
||||
};
|
||||
|
||||
$.ajax(ajaxProp).done(function(res) {
|
||||
if (res.status) {
|
||||
const url = "{{ url('image') }}";
|
||||
alertSuccessWithUrl('Notice', "Delete success", url);
|
||||
hideLoading();
|
||||
} else {
|
||||
alertFail('Notice', res.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
logAjaxError(xhr, status, error);
|
||||
alertFail('Notice', error.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const copyButtons = document.querySelectorAll('.copy-button');
|
||||
|
||||
copyButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
const urlToCopy = button.getAttribute('data-url');
|
||||
|
||||
// Copy the URL to the clipboard
|
||||
navigator.clipboard.writeText(urlToCopy).then(() => {
|
||||
alert(
|
||||
'Link copied to clipboard!'
|
||||
); // You can change this to a toast notification
|
||||
}).catch(err => {
|
||||
console.error('Could not copy text: ', err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Delete folder
|
||||
$(document).on('click', '.delete-folder-item', function() {
|
||||
swal.fire({
|
||||
allowOutsideClick: false,
|
||||
text: "Are you sure you would like to Delete?",
|
||||
icon: "warning",
|
||||
buttonsStyling: false,
|
||||
showDenyButton: true,
|
||||
confirmButtonText: "Yes",
|
||||
denyButtonText: 'No',
|
||||
customClass: {
|
||||
confirmButton: "btn btn-primary",
|
||||
denyButton: "btn btn-light-danger"
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
// set up ajax
|
||||
initAjaxSetupToken();
|
||||
|
||||
const ajaxProp = {
|
||||
url: "{{ url('image/delete-folder') }}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
item_id: $(this).data('id')
|
||||
},
|
||||
};
|
||||
|
||||
$.ajax(ajaxProp).done(function(res) {
|
||||
if (res.status) {
|
||||
const url = "{{ url('image') }}";
|
||||
alertSuccessWithUrl('Notice', "Delete success", url);
|
||||
hideLoading();
|
||||
} else {
|
||||
alertFail('Notice', res.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
logAjaxError(xhr, status, error);
|
||||
alertFail('Notice', error.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,131 @@
|
||||
@extends('layouts.loginTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<form class="form w-100" novalidate="novalidate" id="frm-login" method="post" action="{{ url('authenticate') }}">
|
||||
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
<!--begin::Heading-->
|
||||
<div class="text-center mb-11">
|
||||
<!--begin::Title-->
|
||||
<h1 class="text-dark fw-bolder mb-3">
|
||||
<img src="{{ url('assets/media/logos/footer-logo.png') }}" alt="" />
|
||||
</h1>
|
||||
<!--end::Title-->
|
||||
</div>
|
||||
<!--begin::Heading-->
|
||||
|
||||
|
||||
<!--begin::Input group=-->
|
||||
<div class="fv-row mb-8">
|
||||
<!--begin::Email-->
|
||||
<input type="email" placeholder="Email" name="email" autocomplete="off"
|
||||
class="form-control bg-transparent" />
|
||||
<!--end::Email-->
|
||||
</div>
|
||||
|
||||
<!--end::Input group=-->
|
||||
<div class="fv-row mb-3">
|
||||
<!--begin::Password-->
|
||||
<input id="input-password" type="password" placeholder="Password" name="password" autocomplete="off"
|
||||
class="form-control bg-transparent" />
|
||||
<!--end::Password-->
|
||||
</div>
|
||||
|
||||
<!--end::Input group=-->
|
||||
<!--begin::Wrapper-->
|
||||
<div class="d-flex flex-stack flex-wrap gap-3 fs-base fw-semibold mb-8">
|
||||
<div></div>
|
||||
<!--begin::Link-->
|
||||
{{-- <a href="{{ url('forgot-password') }}" class="link-primary">Forgot
|
||||
Password ?</a> --}}
|
||||
<!--end::Link-->
|
||||
</div>
|
||||
<!--end::Wrapper-->
|
||||
|
||||
<!--begin::Submit button-->
|
||||
<div class="d-grid mb-10">
|
||||
<button type="button" id="btn-login" class="btn btn-primary">
|
||||
<!--begin::Indicator label-->
|
||||
<span class="indicator-label">Sign In</span>
|
||||
<!--end::Indicator label-->
|
||||
<!--begin::Indicator progress-->
|
||||
<span class="indicator-progress">Please wait...
|
||||
<span class="spinner-border spinner-border-sm align-middle ms-2"></span></span>
|
||||
<!--end::Indicator progress-->
|
||||
</button>
|
||||
</div>
|
||||
<!--end::Submit button-->
|
||||
|
||||
</form>
|
||||
|
||||
@stop
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
|
||||
$(document).on("click", "#btn-login", function(e) {
|
||||
|
||||
// handle bomb click
|
||||
e.preventDefault();
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
formSubmit()
|
||||
})
|
||||
|
||||
var inputPassword = document.getElementById("input-password");
|
||||
|
||||
// Execute a function when the user presses a key on the keyboard
|
||||
inputPassword.addEventListener("keypress", function(event) {
|
||||
// If the user presses the "Enter" key on the keyboard
|
||||
if (event.key === "Enter") {
|
||||
// Cancel the default action, if needed
|
||||
event.preventDefault();
|
||||
alertLoading("Loading")
|
||||
// Trigger the button element with a click
|
||||
document.getElementById("btn-login").click();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
function formSubmit() {
|
||||
// form data
|
||||
const form = $('#frm-login')[0];
|
||||
const formData = new FormData(form);
|
||||
|
||||
// set up ajax
|
||||
initAjaxSetupToken();
|
||||
|
||||
const ajaxProp = {
|
||||
url: "{{ url('authenticate') }}",
|
||||
dataType: 'json',
|
||||
method: 'post',
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
};
|
||||
|
||||
$.ajax(ajaxProp).done(function(res) {
|
||||
if (isAjaxStatusSuccess(res.status)) {
|
||||
window.location.href = '{{ url('dashboard') }}';
|
||||
hideLoading();
|
||||
} else {
|
||||
alertFail('Notice', res.message ?? "Login unsuccessfully");
|
||||
hideLoading();
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
logAjaxError(xhr, status, error);
|
||||
alertFail('Notice', error.message ?? "Login unsuccessfully");
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,110 @@
|
||||
@extends('layouts/backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="page-title-box">
|
||||
<h4 class="page-title m-b-20">Profile</h4>
|
||||
<ol class="breadcrumb p-0 m-0">
|
||||
<li>@include('uc.backHome')</li>
|
||||
<li>
|
||||
<a href="{{ url('profile') }}">User</a>
|
||||
</li>
|
||||
<li class="active">
|
||||
Profile
|
||||
</li>
|
||||
</ol>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-12">
|
||||
|
||||
<!-- Message -->
|
||||
<div class="form-group">
|
||||
<div class="form-group">
|
||||
@if (Session::has('messageSuccess'))
|
||||
@include('uc/messageSuccess')
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
@include('uc/messageFail')
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Profile</h3>
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
|
||||
<form class="form-horizontal" action="{{ url('update-profile') }}" method="post"
|
||||
enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
<!-- First Name -->
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label">First Name</label>
|
||||
<div class="col-md-10">
|
||||
<input type="text" id="first_name" class="form-control" name="first_name"
|
||||
value="{{ $profileView->first_name }}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Last Name -->
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label">Last Name</label>
|
||||
<div class="col-md-10">
|
||||
<input type="text" id="last_name" class="form-control" name="last_name"
|
||||
value="{{ $profileView->last_name }}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Password -->
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label">Password</label>
|
||||
<div class="col-md-10">
|
||||
<input type="password" id="password" class="form-control" name="password" value="">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Email -->
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label">Email</label>
|
||||
<div class="col-md-10">
|
||||
<input readonly type="text" id="email" class="form-control" name="email"
|
||||
value="{{ $profileView->email }}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Button -->
|
||||
<div class="text-center">
|
||||
<button type="submit" class="btn btn-success waves-effect waves-light">Save</button>
|
||||
<button type="reset" class="btn btn-danger waves-effect waves-light">Cancel</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
@section('script')
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,122 @@
|
||||
@extends('layouts.loginTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<form class="form w-100" novalidate="novalidate" id="frm-reset-password" method="post"
|
||||
action="{{ url('post-reset-password') }}">
|
||||
|
||||
<input type="hidden" name="userId" value="{{ $userIdView }}">
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
<!--begin::Heading-->
|
||||
<div class="text-center mb-11">
|
||||
<!--begin::Title-->
|
||||
<h1 class="text-dark fw-bolder mb-3">Reset Password</h1>
|
||||
<!--end::Title-->
|
||||
</div>
|
||||
<!--begin::Heading-->
|
||||
|
||||
|
||||
<!--begin::Input group=-->
|
||||
<div class="fv-row mb-8">
|
||||
<!--begin::Email-->
|
||||
<input type="password" placeholder="Password" name="password" autocomplete="off"
|
||||
class="form-control bg-transparent" />
|
||||
<!--end::Email-->
|
||||
</div>
|
||||
|
||||
<!--end::Input group=-->
|
||||
<!--begin::Wrapper-->
|
||||
<div class="d-flex flex-stack flex-wrap gap-3 fs-base fw-semibold mb-8">
|
||||
<div></div>
|
||||
<!--begin::Link-->
|
||||
<a href="{{ url('login') }}" class="link-primary">Login ?</a>
|
||||
<!--end::Link-->
|
||||
</div>
|
||||
<!--end::Wrapper-->
|
||||
|
||||
<!--begin::Submit button-->
|
||||
<div class="d-grid mb-10">
|
||||
<button type="button" id="btn-submit" class="btn btn-primary">
|
||||
<!--begin::Indicator label-->
|
||||
<span class="indicator-label">Submit</span>
|
||||
<!--end::Indicator label-->
|
||||
<!--begin::Indicator progress-->
|
||||
<span class="indicator-progress">Please wait...
|
||||
<span class="spinner-border spinner-border-sm align-middle ms-2"></span></span>
|
||||
<!--end::Indicator progress-->
|
||||
</button>
|
||||
</div>
|
||||
<!--end::Submit button-->
|
||||
|
||||
</form>
|
||||
|
||||
@stop
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
|
||||
$(document).on("click", "#btn-submit", function(e) {
|
||||
|
||||
// handle bomb click
|
||||
e.preventDefault();
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
formSubmit()
|
||||
})
|
||||
|
||||
var inputPassword = document.getElementById("input-password");
|
||||
|
||||
// Execute a function when the user presses a key on the keyboard
|
||||
inputPassword.addEventListener("keypress", function(event) {
|
||||
// If the user presses the "Enter" key on the keyboard
|
||||
if (event.key === "Enter") {
|
||||
// Cancel the default action, if needed
|
||||
event.preventDefault();
|
||||
alertLoading("Loading")
|
||||
// Trigger the button element with a click
|
||||
document.getElementById("btn-submit").click();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
function formSubmit() {
|
||||
// form data
|
||||
const form = $('#frm-reset-password')[0];
|
||||
const formData = new FormData(form);
|
||||
|
||||
// set up ajax
|
||||
initAjaxSetupToken();
|
||||
|
||||
const ajaxProp = {
|
||||
url: "{{ url('post-reset-password') }}",
|
||||
dataType: 'json',
|
||||
method: 'post',
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
};
|
||||
|
||||
$.ajax(ajaxProp).done(function(res) {
|
||||
if (isAjaxStatusSuccess(res.status)) {
|
||||
alertSuccess('Notice', 'Please check your email address')
|
||||
window.location.href = '{{ url('') }}';
|
||||
hideLoading();
|
||||
} else {
|
||||
alertFail('Notice', res.message ?? "Reset password unsuccessfully");
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
logAjaxError(xhr, status, error);
|
||||
alertFail('Notice', error.message ?? "Reset password unsuccessfully");
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,365 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<style>
|
||||
#progressBar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
border-radius: 5px;
|
||||
margin-top: 10px;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.progress-bar::-webkit-progress-value {
|
||||
background-color: #4CAF50;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
margin-top: 10px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'Sound Add',
|
||||
'pageName' => 'Add',
|
||||
'pageParent' => 'Sound Management',
|
||||
'pageParentLink' => url('sound'),
|
||||
])
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
|
||||
|
||||
<form id="frmAdd" class="form d-flex flex-column flex-lg-row" method="post"
|
||||
enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<div class="mb-10">
|
||||
<label class="form-label required">File Sound</label>
|
||||
|
||||
<input class="fileInput file-input" type="file" id="fileInput" name="fileInput"
|
||||
multiple accept=".m4a, .mp4, .mp3, .wav">
|
||||
|
||||
<progress id="progressBar" class="progress-bar" value="0"
|
||||
max="100"></progress>
|
||||
<div id="progressText" class="progress-text">0%</div>
|
||||
|
||||
<div class="text-muted fs-7">Allowed Types .m4a, .mp4, .mp3, .wav</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('sound') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button type="button" id="btn_submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script>
|
||||
const baseApiUrl = "{{ env('API_URL') }}";
|
||||
|
||||
$(document).on("click", "#btn_submit", async function(e) {
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
await uploadFile();
|
||||
|
||||
});
|
||||
|
||||
|
||||
// Step 1
|
||||
async function uploadFile() {
|
||||
const fileInput = document.getElementById("fileInput");
|
||||
const progressBar = document.getElementById("progressBar");
|
||||
const progressText = document.getElementById("progressText");
|
||||
|
||||
if (!fileInput || fileInput.files.length === 0) {
|
||||
alertFail("Notice", "Please select one or more files.");
|
||||
hideLoading();
|
||||
return;
|
||||
}
|
||||
|
||||
const files = Array.from(fileInput.files); // Get all selected files
|
||||
$("#progressBar").show();
|
||||
|
||||
let totalSize = files.reduce((sum, file) => sum + file.size, 0);
|
||||
let totalUploadedSize = 0;
|
||||
|
||||
// Upload all files sequentially
|
||||
for (const file of files) {
|
||||
await uploadSingleFile(file, progressBar, progressText, totalSize, (fileUploadedSize) => {
|
||||
totalUploadedSize += fileUploadedSize;
|
||||
const overallPercent = Math.floor((totalUploadedSize / totalSize) * 100);
|
||||
animateProgress(progressBar, progressText, overallPercent);
|
||||
});
|
||||
}
|
||||
|
||||
const folderId = "{{ $folderIdView }}";
|
||||
let redirectUrl = "{{ url('sound') }}"
|
||||
if (folderId) {
|
||||
redirectUrl = `${redirectUrl}/folder/${folderId}`;
|
||||
}
|
||||
alertSuccessWithUrl("Notice", "All files uploaded successfully", redirectUrl);
|
||||
}
|
||||
|
||||
async function uploadSingleFile(file, progressBar, progressText, totalSize, updateOverallProgress) {
|
||||
const uploadId = await initiateMultipartUpload(file.name);
|
||||
const partSize = 500 * 1024 * 1024; // 500 MB per part
|
||||
const parts = [];
|
||||
let uploadedSize = 0;
|
||||
|
||||
const uploadPromises = Array.from({
|
||||
length: Math.ceil(file.size / partSize)
|
||||
},
|
||||
(_, index) => {
|
||||
const partNumber = index + 1;
|
||||
const chunk = file.slice(index * partSize, (index + 1) * partSize);
|
||||
|
||||
return (async () => {
|
||||
const presignedUrl = await getPresignedUrl(uploadId, partNumber, file.name);
|
||||
const etag = await uploadPartToS3(presignedUrl, chunk);
|
||||
|
||||
parts.push({
|
||||
PartNumber: partNumber,
|
||||
ETag: etag
|
||||
});
|
||||
|
||||
uploadedSize += chunk.size;
|
||||
updateOverallProgress(chunk.size); // Update the overall progress
|
||||
})();
|
||||
}
|
||||
);
|
||||
|
||||
await Promise.all(uploadPromises);
|
||||
await completeMultipartUpload(uploadId, parts, file.name);
|
||||
await saveFileNameToDB(file.name);
|
||||
}
|
||||
|
||||
// Step 2
|
||||
async function initiateMultipartUpload(fileName) {
|
||||
const urlUploadImage = `${baseApiUrl}/initiate-multipart-upload`;
|
||||
const response = await fetch(
|
||||
urlUploadImage, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
fileName
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
const {
|
||||
uploadId
|
||||
} = await response.json();
|
||||
|
||||
return uploadId;
|
||||
}
|
||||
|
||||
// Step 3
|
||||
async function getPresignedUrl(uploadId, partNumber, fileName) {
|
||||
|
||||
const urlPresigned = `${baseApiUrl}/get-presigned-url`
|
||||
const response = await fetch(
|
||||
urlPresigned, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
uploadId,
|
||||
partNumber,
|
||||
fileName
|
||||
}),
|
||||
}
|
||||
);
|
||||
const {
|
||||
url
|
||||
} = await response.json();
|
||||
return url;
|
||||
}
|
||||
|
||||
// Step 4
|
||||
async function uploadPartToS3(url, chunk) {
|
||||
const response = await fetch(url, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/octet-stream",
|
||||
},
|
||||
body: chunk,
|
||||
});
|
||||
if (!response.ok) {
|
||||
alertFail("Notice", "Failed to upload part")
|
||||
hideLoading();
|
||||
//throw new Error("Failed to upload part");
|
||||
}
|
||||
|
||||
const etag = `${response.headers.get("ETag")}`.replace(/"/g, "");
|
||||
|
||||
if (!etag) {
|
||||
throw new Error("Failed to retrieve ETag from the response.");
|
||||
}
|
||||
|
||||
return etag;
|
||||
}
|
||||
|
||||
// Step 5
|
||||
async function completeMultipartUpload(uploadId, parts, fileName) {
|
||||
const urlUploadComplete = `${baseApiUrl}/complete-multipart-upload`;
|
||||
const response = await fetch(urlUploadComplete, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
uploadId,
|
||||
parts,
|
||||
fileName
|
||||
}),
|
||||
});
|
||||
if (response.ok) {
|
||||
//window.location.href = "{{ url('image') }}";
|
||||
} else {
|
||||
alertFail("Notice", "Failed to upload part");
|
||||
hideLoading();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Smoothly animates the progress bar and percentage text.
|
||||
*/
|
||||
async function animateProgress(progressBar, progressText, targetPercent) {
|
||||
const currentPercent = parseInt(progressBar.value) || 0;
|
||||
// Increment the percentage smoothly
|
||||
for (let percent = currentPercent + 1; percent <= targetPercent; percent++) {
|
||||
progressBar.value = percent;
|
||||
progressText.textContent = `${percent}%`;
|
||||
|
||||
// Add a small delay to make the increment visible (10ms delay)
|
||||
await new Promise((resolve) => setTimeout(resolve, 10));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the uploaded file name to the server using AJAX.
|
||||
*/
|
||||
function saveFileNameToDB(fileName) {
|
||||
initAjaxSetupToken();
|
||||
|
||||
const folderId = "{{ $folderIdView }}";
|
||||
const url = "{{ url('') }}";
|
||||
|
||||
return $.ajax({
|
||||
url: `${url}/sound/insert`,
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({
|
||||
fileName,
|
||||
folderId
|
||||
}),
|
||||
success: (response) => {
|
||||
console.log('File name saved:', response);
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Error saving file name:', err);
|
||||
alertFail("Notice", "There was an error saving the file name.");
|
||||
hideLoading();
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
$('.file-input').fileuploader({
|
||||
extensions: ['m4a', 'mp4', 'mp3', 'wav'],
|
||||
limit: null,
|
||||
fileMaxSize: null,
|
||||
changeInput: '<div class="fileuploader-input">' +
|
||||
'<div class="fileuploader-input-inner">' +
|
||||
'<p><i class="fileuploader-icon-main"></i></p>' +
|
||||
'<h6>Drag and drop files here</h6>' +
|
||||
'<p>or</p>' +
|
||||
'<br>' +
|
||||
'<button type="button" class="fileuploader-input-button"><span>${captions.button}</span></button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
theme: 'dragdrop',
|
||||
});
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,95 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'Sound Create Folder',
|
||||
'pageName' => 'Create folder',
|
||||
'pageParent' => 'Sound Management',
|
||||
'pageParentLink' => url('sound'),
|
||||
])
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
<form id="frmAdd" action="{{ url('sound/insert-folder') }}" class="form d-flex flex-column flex-lg-row"
|
||||
method="post" enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Name</label>
|
||||
<input type="text" name="name" class="form-control mb-2 col-6"
|
||||
value="{{ old('name') }}" />
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('sound') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script></script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,96 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'Sound Edit Folder',
|
||||
'pageName' => 'Edit folder',
|
||||
'pageParent' => 'Sound Management',
|
||||
'pageParentLink' => url('sound'),
|
||||
])
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
<form id="frmAdd" action="{{ url('sound/update-folder') }}" class="form d-flex flex-column flex-lg-row"
|
||||
method="post" enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="id" value="{{ $idView }}">
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Name</label>
|
||||
<input type="text" name="name" class="form-control mb-2 col-6"
|
||||
value="{{ $itemView->name }}" />
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('sound') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script></script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,311 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<style>
|
||||
.link-container {
|
||||
display: flex;
|
||||
/* Use flexbox for alignment */
|
||||
align-items: center;
|
||||
/* Center items vertically */
|
||||
justify-content: space-between;
|
||||
/* Space between the URL and button */
|
||||
}
|
||||
|
||||
.file-url {
|
||||
flex: 1;
|
||||
/* Allow the URL to take up available space */
|
||||
color: #007bff;
|
||||
/* Link color */
|
||||
text-decoration: none;
|
||||
/* Remove underline */
|
||||
overflow: hidden;
|
||||
/* Hide overflow */
|
||||
white-space: nowrap;
|
||||
/* Prevent text wrapping */
|
||||
text-overflow: ellipsis;
|
||||
/* Add ellipsis for overflow */
|
||||
margin-right: 10px;
|
||||
/* Space between text and button */
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.breadcrumbList', [
|
||||
'title' => 'Sound Management Folder ' . $folderView->name,
|
||||
'pageName' => 'Sound Management',
|
||||
])
|
||||
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
<div class="card">
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<div class="card-header border-0 pt-6">
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
</div>
|
||||
|
||||
@if (Auth::user()->role != 2)
|
||||
<div class="card-toolbar">
|
||||
<div class="d-flex justify-content-end" data-kt-customer-table-toolbar="base">
|
||||
<a href="{{ url('sound/add/' . $folderView->id) }}" class="btn btn-primary">Add
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card-header border-0 pt-5">
|
||||
|
||||
<div class="card-title">
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
<span class="svg-icon svg-icon-1 position-absolute ms-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<rect opacity="0.5" x="17.0365" y="15.1223" width="8.15546" height="2"
|
||||
rx="1" transform="rotate(45 17.0365 15.1223)" fill="currentColor">
|
||||
</rect>
|
||||
<path
|
||||
d="M11 19C6.55556 19 3 15.4444 3 11C3 6.55556 6.55556 3 11 3C15.4444 3 19 6.55556 19 11C19 15.4444 15.4444 19 11 19ZM11 5C7.53333 5 5 7.53333 5 11C5 14.4667 7.53333 17 11 17C14.4667 17 17 14.4667 17 11C17 7.53333 14.4667 5 11 5Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<input type="text" table-filter="search"
|
||||
class="form-control form-control-solid w-250px ps-15" placeholder="Search" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-body py-4">
|
||||
<!--begin::Table-->
|
||||
<table class="table align-middle table-row-dashed fs-6 gy-5" id="data-table">
|
||||
<!--begin::Table head-->
|
||||
<thead>
|
||||
<!--begin::Table row-->
|
||||
<tr class="text-start text-muted fw-bold fs-7 text-uppercase gs-0">
|
||||
<th class="min-w-125px">Name</th>
|
||||
<th class="min-w-125px">Created</th>
|
||||
<th class="text-end min-w-100px">Manage</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="text-gray-600 fw-semibold">
|
||||
|
||||
@foreach ($itemView as $obj)
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex flex-column">
|
||||
<a href="#" class="text-gray-800 text-hover-primary mb-1">
|
||||
|
||||
<audio controls class="me-3">
|
||||
<source src="{{ env('R2_SCHEMA_URL') . $obj['name'] }}"
|
||||
type="audio/mp4">
|
||||
Your browser does not support the audio element.
|
||||
</audio>
|
||||
</a>
|
||||
<span>{{ $obj['name'] }}</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
|
||||
<td>
|
||||
{{ Carbon\Carbon::parse($obj['created_at'])->format('d, M Y') }}
|
||||
</td>
|
||||
|
||||
<td class="min-w-100px text-end">
|
||||
|
||||
{{-- Download --}}
|
||||
<a href="{{ env('R2_SCHEMA_URL') . $obj['name'] }}" target="_blank"
|
||||
class="btn btn-sm btn-icon btn-light btn-active-light-primary"
|
||||
type="button" data-bs-toggle="tooltip" aria-label="Coming soon"
|
||||
data-bs-original-title="Coming soon" data-kt-initialized="1">
|
||||
<i class="bi bi-download fs-3"></i>
|
||||
</a>
|
||||
|
||||
{{-- Copy --}}
|
||||
<button type="button" data-action="copy"
|
||||
data-url="{{ env('R2_SCHEMA_URL') . $obj['name'] }}"
|
||||
class="btn btn-sm btn-icon btn-light btn-active-light-primary copy-button">
|
||||
<span class="svg-icon svg-icon-2">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.5"
|
||||
d="M18 2H9C7.34315 2 6 3.34315 6 5H8C8 4.44772 8.44772 4 9 4H18C18.5523 4 19 4.44772 19 5V16C19 16.5523 18.5523 17 18 17V19C19.6569 19 21 17.6569 21 16V5C21 3.34315 19.6569 2 18 2Z"
|
||||
fill="currentColor"></path>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M14.7857 7.125H6.21429C5.62255 7.125 5.14286 7.6007 5.14286 8.1875V18.8125C5.14286 19.3993 5.62255 19.875 6.21429 19.875H14.7857C15.3774 19.875 15.8571 19.3993 15.8571 18.8125V8.1875C15.8571 7.6007 15.3774 7.125 14.7857 7.125ZM6.21429 5C4.43908 5 3 6.42709 3 8.1875V18.8125C3 20.5729 4.43909 22 6.21429 22H14.7857C16.5609 22 18 20.5729 18 18.8125V8.1875C18 6.42709 16.5609 5 14.7857 5H6.21429Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<!--end::Svg Icon-->
|
||||
</button>
|
||||
|
||||
|
||||
{{-- Delete --}}
|
||||
@if (Auth::user()->role != 2)
|
||||
<a href="#" data-id="{{ $obj['id'] }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm delete-item">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5 9C5 8.44772 5.44772 8 6 8H18C18.5523 8 19 8.44772 19 9V18C19 19.6569 17.6569 21 16 21H8C6.34315 21 5 19.6569 5 18V9Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M5 5C5 4.44772 5.44772 4 6 4H18C18.5523 4 19 4.44772 19 5V5C19 5.55228 18.5523 6 18 6H6C5.44772 6 5 5.55228 5 5V5Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M9 4C9 3.44772 9.44772 3 10 3H14C14.5523 3 15 3.44772 15 4V4H9V4Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
const baseUrl = "{{ url('sound') }}";
|
||||
var datatable;
|
||||
datatable = $("#data-table").DataTable({
|
||||
"info": false,
|
||||
"order": [],
|
||||
"pageLength": 25,
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, 500, 1000],
|
||||
[10, 25, 50, 100, 500, 1000]
|
||||
]
|
||||
});
|
||||
|
||||
// Filter by search
|
||||
const filterSearch = document.querySelector('[table-filter="search"]');
|
||||
filterSearch.addEventListener('keyup', function(e) {
|
||||
datatable.search(e.target.value).draw();
|
||||
});
|
||||
|
||||
// filter by status
|
||||
const filterStatus = document.querySelector('[table-filter="status"]');
|
||||
$(filterStatus).on('change', e => {
|
||||
let value = e.target.value;
|
||||
if (value === 'all') {
|
||||
value = '';
|
||||
}
|
||||
datatable.column(4).search(value).draw();
|
||||
});
|
||||
|
||||
|
||||
// Remove
|
||||
$(document).on('click', '.delete-item', function() {
|
||||
swal.fire({
|
||||
allowOutsideClick: false,
|
||||
text: "Are you sure you would like to Delete?",
|
||||
icon: "warning",
|
||||
buttonsStyling: false,
|
||||
showDenyButton: true,
|
||||
confirmButtonText: "Yes",
|
||||
denyButtonText: 'No',
|
||||
customClass: {
|
||||
confirmButton: "btn btn-primary",
|
||||
denyButton: "btn btn-light-danger"
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
// set up ajax
|
||||
initAjaxSetupToken();
|
||||
|
||||
const ajaxProp = {
|
||||
url: "{{ url('sound/delete') }}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
item_id: $(this).data('id')
|
||||
},
|
||||
};
|
||||
|
||||
// const id = $(this).data('id');
|
||||
const id = "{{ $folderView->id }}";
|
||||
|
||||
$.ajax(ajaxProp).done(function(res) {
|
||||
if (res.status) {
|
||||
const url = "{{ url('sound/folder') }}/" + id;
|
||||
alertSuccessWithUrl('Notice', "Delete success", url);
|
||||
hideLoading();
|
||||
} else {
|
||||
alertFail('Notice', res.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
logAjaxError(xhr, status, error);
|
||||
alertFail('Notice', error.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const copyButtons = document.querySelectorAll('.copy-button');
|
||||
|
||||
copyButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
const urlToCopy = button.getAttribute('data-url');
|
||||
|
||||
// Copy the URL to the clipboard
|
||||
navigator.clipboard.writeText(urlToCopy).then(() => {
|
||||
alert(
|
||||
'Link copied to clipboard!'
|
||||
); // You can change this to a toast notification
|
||||
}).catch(err => {
|
||||
console.error('Could not copy text: ', err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,440 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<style>
|
||||
.link-container {
|
||||
display: flex;
|
||||
/* Use flexbox for alignment */
|
||||
align-items: center;
|
||||
/* Center items vertically */
|
||||
justify-content: space-between;
|
||||
/* Space between the URL and button */
|
||||
}
|
||||
|
||||
.file-url {
|
||||
flex: 1;
|
||||
/* Allow the URL to take up available space */
|
||||
color: #007bff;
|
||||
/* Link color */
|
||||
text-decoration: none;
|
||||
/* Remove underline */
|
||||
overflow: hidden;
|
||||
/* Hide overflow */
|
||||
white-space: nowrap;
|
||||
/* Prevent text wrapping */
|
||||
text-overflow: ellipsis;
|
||||
/* Add ellipsis for overflow */
|
||||
margin-right: 10px;
|
||||
/* Space between text and button */
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.breadcrumbList', [
|
||||
'title' => 'Sound Management',
|
||||
'pageName' => 'Sound Management',
|
||||
])
|
||||
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
<div class="card">
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<div class="card-header border-0 pt-6">
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
</div>
|
||||
|
||||
@if (Auth::user()->role != 2)
|
||||
<div class="card-toolbar">
|
||||
|
||||
<div class="d-flex justify-content-end" style="margin-right: 5px;"
|
||||
data-kt-customer-table-toolbar="base">
|
||||
<a href="{{ url('sound/add-folder') }}" class="btn btn-light-primary me-3"
|
||||
id="kt_file_manager_new_folder">New
|
||||
Folder</a>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end" data-kt-customer-table-toolbar="base">
|
||||
<a href="{{ url('sound/add') }}" class="btn btn-primary">Add </a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card-header border-0 pt-5">
|
||||
|
||||
<div class="card-title">
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
<span class="svg-icon svg-icon-1 position-absolute ms-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<rect opacity="0.5" x="17.0365" y="15.1223" width="8.15546" height="2"
|
||||
rx="1" transform="rotate(45 17.0365 15.1223)" fill="currentColor">
|
||||
</rect>
|
||||
<path
|
||||
d="M11 19C6.55556 19 3 15.4444 3 11C3 6.55556 6.55556 3 11 3C15.4444 3 19 6.55556 19 11C19 15.4444 15.4444 19 11 19ZM11 5C7.53333 5 5 7.53333 5 11C5 14.4667 7.53333 17 11 17C14.4667 17 17 14.4667 17 11C17 7.53333 14.4667 5 11 5Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<input type="text" table-filter="search"
|
||||
class="form-control form-control-solid w-250px ps-15" placeholder="Search" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-body py-4">
|
||||
<!--begin::Table-->
|
||||
<table class="table align-middle table-row-dashed fs-6 gy-5" id="data-table">
|
||||
<!--begin::Table head-->
|
||||
<thead>
|
||||
<!--begin::Table row-->
|
||||
<tr class="text-start text-muted fw-bold fs-7 text-uppercase gs-0">
|
||||
<th class="min-w-125px">Name</th>
|
||||
<th class="min-w-125px">Created</th>
|
||||
<th class="text-end min-w-100px">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="text-gray-600 fw-semibold">
|
||||
@foreach ($folderView as $obj)
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<span class="svg-icon svg-icon-2x svg-icon-primary me-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3" d="M10 4H21C21.6 4 22 4.4 22 5V7H10V4Z"
|
||||
fill="currentColor"></path>
|
||||
<path
|
||||
d="M9.2 3H3C2.4 3 2 3.4 2 4V19C2 19.6 2.4 20 3 20H21C21.6 20 22 19.6 22 19V7C22 6.4 21.6 6 21 6H12L10.4 3.60001C10.2 3.20001 9.7 3 9.2 3Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<a href="{{ url('sound/folder/' . $obj->id) }}"
|
||||
class="text-gray-800 text-hover-primary">
|
||||
{{ $obj->name }}</a>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ Carbon\Carbon::parse($obj['created_at'])->format('d, M Y') }}
|
||||
</td>
|
||||
|
||||
<td class="min-w-100px text-end">
|
||||
|
||||
{{-- Download --}}
|
||||
<a href="{{ url('sound/download-folder') . '/' . $obj->id }}"
|
||||
class="btn-download-folder btn btn-sm btn-icon btn-light btn-active-light-primary"
|
||||
type="button" data-bs-toggle="tooltip" aria-label="Coming soon"
|
||||
data-bs-original-title="Coming soon" data-kt-initialized="1">
|
||||
<i class="bi bi-download fs-3"></i>
|
||||
</a>
|
||||
|
||||
{{-- Edit --}}
|
||||
<a href="{{ url('sound/edit-folder/' . $obj['id']) }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm me-1">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21.4 8.35303L19.241 10.511L13.485 4.755L15.643 2.59595C16.0248 2.21423 16.5426 1.99988 17.0825 1.99988C17.6224 1.99988 18.1402 2.21423 18.522 2.59595L21.4 5.474C21.7817 5.85581 21.9962 6.37355 21.9962 6.91345C21.9962 7.45335 21.7817 7.97122 21.4 8.35303ZM3.68699 21.932L9.88699 19.865L4.13099 14.109L2.06399 20.309C1.98815 20.5354 1.97703 20.7787 2.03189 21.0111C2.08674 21.2436 2.2054 21.4561 2.37449 21.6248C2.54359 21.7934 2.75641 21.9115 2.989 21.9658C3.22158 22.0201 3.4647 22.0084 3.69099 21.932H3.68699Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M5.574 21.3L3.692 21.928C3.46591 22.0032 3.22334 22.0141 2.99144 21.9594C2.75954 21.9046 2.54744 21.7864 2.3789 21.6179C2.21036 21.4495 2.09202 21.2375 2.03711 21.0056C1.9822 20.7737 1.99289 20.5312 2.06799 20.3051L2.696 18.422L5.574 21.3ZM4.13499 14.105L9.891 19.861L19.245 10.507L13.489 4.75098L4.13499 14.105Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{{-- Delete --}}
|
||||
<a href="#" data-id="{{ $obj['id'] }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm delete-folder-item">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5 9C5 8.44772 5.44772 8 6 8H18C18.5523 8 19 8.44772 19 9V18C19 19.6569 17.6569 21 16 21H8C6.34315 21 5 19.6569 5 18V9Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M5 5C5 4.44772 5.44772 4 6 4H18C18.5523 4 19 4.44772 19 5V5C19 5.55228 18.5523 6 18 6H6C5.44772 6 5 5.55228 5 5V5Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M9 4C9 3.44772 9.44772 3 10 3H14C14.5523 3 15 3.44772 15 4V4H9V4Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
@foreach ($itemView as $obj)
|
||||
<tr>
|
||||
<td class="d-flex align-items-center">
|
||||
<div class="d-flex flex-column">
|
||||
<a href="#" class="text-gray-800 text-hover-primary mb-1">
|
||||
|
||||
<audio controls class="me-3">
|
||||
<source src="{{ env('R2_SCHEMA_URL') . $obj['name'] }}"
|
||||
type="audio/mp4">
|
||||
Your browser does not support the audio element.
|
||||
</audio>
|
||||
</a>
|
||||
<span>{{ $obj['name'] }}</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
|
||||
<td>
|
||||
{{ Carbon\Carbon::parse($obj['created_at'])->format('d, M Y') }}
|
||||
</td>
|
||||
|
||||
|
||||
<td class="min-w-100px text-end">
|
||||
|
||||
{{-- Download --}}
|
||||
<a href="{{ env('R2_SCHEMA_URL') . $obj['name'] }}" target="_blank"
|
||||
class="btn btn-sm btn-icon btn-light btn-active-light-primary"
|
||||
type="button" data-bs-toggle="tooltip" aria-label="Coming soon"
|
||||
data-bs-original-title="Coming soon" data-kt-initialized="1">
|
||||
<i class="bi bi-download fs-3"></i>
|
||||
</a>
|
||||
|
||||
{{-- Copy --}}
|
||||
<button type="button" data-action="copy"
|
||||
data-url="{{ env('R2_SCHEMA_URL') . $obj['name'] }}"
|
||||
class="btn btn-sm btn-icon btn-light btn-active-light-primary copy-button">
|
||||
<span class="svg-icon svg-icon-2">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.5"
|
||||
d="M18 2H9C7.34315 2 6 3.34315 6 5H8C8 4.44772 8.44772 4 9 4H18C18.5523 4 19 4.44772 19 5V16C19 16.5523 18.5523 17 18 17V19C19.6569 19 21 17.6569 21 16V5C21 3.34315 19.6569 2 18 2Z"
|
||||
fill="currentColor"></path>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M14.7857 7.125H6.21429C5.62255 7.125 5.14286 7.6007 5.14286 8.1875V18.8125C5.14286 19.3993 5.62255 19.875 6.21429 19.875H14.7857C15.3774 19.875 15.8571 19.3993 15.8571 18.8125V8.1875C15.8571 7.6007 15.3774 7.125 14.7857 7.125ZM6.21429 5C4.43908 5 3 6.42709 3 8.1875V18.8125C3 20.5729 4.43909 22 6.21429 22H14.7857C16.5609 22 18 20.5729 18 18.8125V8.1875C18 6.42709 16.5609 5 14.7857 5H6.21429Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<!--end::Svg Icon-->
|
||||
</button>
|
||||
|
||||
|
||||
{{-- Delete --}}
|
||||
@if (Auth::user()->role != 2)
|
||||
<a href="#" data-id="{{ $obj['id'] }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm delete-item">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5 9C5 8.44772 5.44772 8 6 8H18C18.5523 8 19 8.44772 19 9V18C19 19.6569 17.6569 21 16 21H8C6.34315 21 5 19.6569 5 18V9Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M5 5C5 4.44772 5.44772 4 6 4H18C18.5523 4 19 4.44772 19 5V5C19 5.55228 18.5523 6 18 6H6C5.44772 6 5 5.55228 5 5V5Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M9 4C9 3.44772 9.44772 3 10 3H14C14.5523 3 15 3.44772 15 4V4H9V4Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
const baseUrl = "{{ url('sound') }}";
|
||||
var datatable;
|
||||
datatable = $("#data-table").DataTable({
|
||||
"info": false,
|
||||
"order": [],
|
||||
"pageLength": 25,
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, 500, 1000],
|
||||
[10, 25, 50, 100, 500, 1000]
|
||||
]
|
||||
});
|
||||
|
||||
// Filter by search
|
||||
const filterSearch = document.querySelector('[table-filter="search"]');
|
||||
filterSearch.addEventListener('keyup', function(e) {
|
||||
datatable.search(e.target.value).draw();
|
||||
});
|
||||
|
||||
// filter by status
|
||||
const filterStatus = document.querySelector('[table-filter="status"]');
|
||||
$(filterStatus).on('change', e => {
|
||||
let value = e.target.value;
|
||||
if (value === 'all') {
|
||||
value = '';
|
||||
}
|
||||
datatable.column(4).search(value).draw();
|
||||
});
|
||||
|
||||
|
||||
// Remove
|
||||
$(document).on('click', '.delete-item', function() {
|
||||
swal.fire({
|
||||
allowOutsideClick: false,
|
||||
text: "Are you sure you would like to Delete?",
|
||||
icon: "warning",
|
||||
buttonsStyling: false,
|
||||
showDenyButton: true,
|
||||
confirmButtonText: "Yes",
|
||||
denyButtonText: 'No',
|
||||
customClass: {
|
||||
confirmButton: "btn btn-primary",
|
||||
denyButton: "btn btn-light-danger"
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
// set up ajax
|
||||
initAjaxSetupToken();
|
||||
|
||||
const ajaxProp = {
|
||||
url: "{{ url('sound/delete') }}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
item_id: $(this).data('id')
|
||||
},
|
||||
};
|
||||
|
||||
$.ajax(ajaxProp).done(function(res) {
|
||||
if (res.status) {
|
||||
const url = "{{ url('sound') }}";
|
||||
alertSuccessWithUrl('Notice', "Delete success", url);
|
||||
hideLoading();
|
||||
} else {
|
||||
alertFail('Notice', res.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
logAjaxError(xhr, status, error);
|
||||
alertFail('Notice', error.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const copyButtons = document.querySelectorAll('.copy-button');
|
||||
|
||||
copyButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
const urlToCopy = button.getAttribute('data-url');
|
||||
|
||||
// Copy the URL to the clipboard
|
||||
navigator.clipboard.writeText(urlToCopy).then(() => {
|
||||
alert(
|
||||
'Link copied to clipboard!'
|
||||
); // You can change this to a toast notification
|
||||
}).catch(err => {
|
||||
console.error('Could not copy text: ', err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Delete folder
|
||||
$(document).on('click', '.delete-folder-item', function() {
|
||||
swal.fire({
|
||||
allowOutsideClick: false,
|
||||
text: "Are you sure you would like to Delete?",
|
||||
icon: "warning",
|
||||
buttonsStyling: false,
|
||||
showDenyButton: true,
|
||||
confirmButtonText: "Yes",
|
||||
denyButtonText: 'No',
|
||||
customClass: {
|
||||
confirmButton: "btn btn-primary",
|
||||
denyButton: "btn btn-light-danger"
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
// set up ajax
|
||||
initAjaxSetupToken();
|
||||
|
||||
const ajaxProp = {
|
||||
url: "{{ url('sound/delete-folder') }}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
item_id: $(this).data('id')
|
||||
},
|
||||
};
|
||||
|
||||
$.ajax(ajaxProp).done(function(res) {
|
||||
if (res.status) {
|
||||
const url = "{{ url('sound') }}";
|
||||
alertSuccessWithUrl('Notice', "Delete success", url);
|
||||
hideLoading();
|
||||
} else {
|
||||
alertFail('Notice', res.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
logAjaxError(xhr, status, error);
|
||||
alertFail('Notice', error.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,472 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'WHERE ELSE : Add Sub Category',
|
||||
'pageName' => 'Add',
|
||||
'pageParent' => 'Sub Category Management',
|
||||
'pageParentLink' => url('where-else/sub-category'),
|
||||
])
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
|
||||
|
||||
<form id="frmAdd" class="form d-flex flex-column flex-lg-row"
|
||||
action="{{ url('where-else/insert-sub-category') }}" method="post" enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
<div class="d-flex flex-column gap-7 gap-lg-10 w-100 w-lg-300px mb-7 me-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
<div class="card-body text-center pt-0">
|
||||
|
||||
<style>
|
||||
.image-input-placeholder {
|
||||
background-image: url('{{ url('assets/media/svg/files/blank-image.svg') }}');
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .image-input-placeholder {
|
||||
background-image: url('../media/svg/files/blank-image-dark.svg');
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="image-input image-input-empty image-input-outline image-input-placeholder mb-3"
|
||||
data-kt-image-input="true">
|
||||
|
||||
<div class="image-input-wrapper w-150px h-150px"></div>
|
||||
|
||||
<label
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="change" data-bs-toggle="tooltip"
|
||||
title="Change avatar">
|
||||
|
||||
<i class="bi bi-pencil-fill fs-7"></i>
|
||||
|
||||
<input type="file" name="avatar" accept=".png, .jpg, .jpeg" />
|
||||
<input type="hidden" name="avatar_remove" />
|
||||
|
||||
</label>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="cancel" data-bs-toggle="tooltip"
|
||||
title="Cancel avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="remove" data-bs-toggle="tooltip"
|
||||
title="Remove avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="text-muted fs-7">Set the profile picture. Only *.png, *.jpg and *.jpeg
|
||||
image
|
||||
files are accepted</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{-- Active --}}
|
||||
<div class="card-header" style="border: unset;">
|
||||
<div class="required card-title">
|
||||
<h2>Active</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<label class="form-check form-switch form-check-custom form-check-solid">
|
||||
<input class="form-check-input" disabled readonly name="active" type="checkbox"
|
||||
value="1" checked />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
|
||||
{{-- <div class="mb-10 fv-row">
|
||||
<label class="required form-label">Date</label>
|
||||
<div class="position-relative d-flex align-items-center">
|
||||
<span class="svg-icon svg-icon-2 position-absolute mx-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21 22H3C2.4 22 2 21.6 2 21V5C2 4.4 2.4 4 3 4H21C21.6 4 22 4.4 22 5V21C22 21.6 21.6 22 21 22Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M6 6C5.4 6 5 5.6 5 5V3C5 2.4 5.4 2 6 2C6.6 2 7 2.4 7 3V5C7 5.6 6.6 6 6 6ZM11 5V3C11 2.4 10.6 2 10 2C9.4 2 9 2.4 9 3V5C9 5.6 9.4 6 10 6C10.6 6 11 5.6 11 5ZM15 5V3C15 2.4 14.6 2 14 2C13.4 2 13 2.4 13 3V5C13 5.6 13.4 6 14 6C14.6 6 15 5.6 15 5ZM19 5V3C19 2.4 18.6 2 18 2C17.4 2 17 2.4 17 3V5C17 5.6 17.4 6 18 6C18.6 6 19 5.6 19 5Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M8.8 13.1C9.2 13.1 9.5 13 9.7 12.8C9.9 12.6 10.1 12.3 10.1 11.9C10.1 11.6 10 11.3 9.8 11.1C9.6 10.9 9.3 10.8 9 10.8C8.8 10.8 8.59999 10.8 8.39999 10.9C8.19999 11 8.1 11.1 8 11.2C7.9 11.3 7.8 11.4 7.7 11.6C7.6 11.8 7.5 11.9 7.5 12.1C7.5 12.2 7.4 12.2 7.3 12.3C7.2 12.4 7.09999 12.4 6.89999 12.4C6.69999 12.4 6.6 12.3 6.5 12.2C6.4 12.1 6.3 11.9 6.3 11.7C6.3 11.5 6.4 11.3 6.5 11.1C6.6 10.9 6.8 10.7 7 10.5C7.2 10.3 7.49999 10.1 7.89999 10C8.29999 9.90003 8.60001 9.80003 9.10001 9.80003C9.50001 9.80003 9.80001 9.90003 10.1 10C10.4 10.1 10.7 10.3 10.9 10.4C11.1 10.5 11.3 10.8 11.4 11.1C11.5 11.4 11.6 11.6 11.6 11.9C11.6 12.3 11.5 12.6 11.3 12.9C11.1 13.2 10.9 13.5 10.6 13.7C10.9 13.9 11.2 14.1 11.4 14.3C11.6 14.5 11.8 14.7 11.9 15C12 15.3 12.1 15.5 12.1 15.8C12.1 16.2 12 16.5 11.9 16.8C11.8 17.1 11.5 17.4 11.3 17.7C11.1 18 10.7 18.2 10.3 18.3C9.9 18.4 9.5 18.5 9 18.5C8.5 18.5 8.1 18.4 7.7 18.2C7.3 18 7 17.8 6.8 17.6C6.6 17.4 6.4 17.1 6.3 16.8C6.2 16.5 6.10001 16.3 6.10001 16.1C6.10001 15.9 6.2 15.7 6.3 15.6C6.4 15.5 6.6 15.4 6.8 15.4C6.9 15.4 7.00001 15.4 7.10001 15.5C7.20001 15.6 7.3 15.6 7.3 15.7C7.5 16.2 7.7 16.6 8 16.9C8.3 17.2 8.6 17.3 9 17.3C9.2 17.3 9.5 17.2 9.7 17.1C9.9 17 10.1 16.8 10.3 16.6C10.5 16.4 10.5 16.1 10.5 15.8C10.5 15.3 10.4 15 10.1 14.7C9.80001 14.4 9.50001 14.3 9.10001 14.3C9.00001 14.3 8.9 14.3 8.7 14.3C8.5 14.3 8.39999 14.3 8.39999 14.3C8.19999 14.3 7.99999 14.2 7.89999 14.1C7.79999 14 7.7 13.8 7.7 13.7C7.7 13.5 7.79999 13.4 7.89999 13.2C7.99999 13 8.2 13 8.5 13H8.8V13.1ZM15.3 17.5V12.2C14.3 13 13.6 13.3 13.3 13.3C13.1 13.3 13 13.2 12.9 13.1C12.8 13 12.7 12.8 12.7 12.6C12.7 12.4 12.8 12.3 12.9 12.2C13 12.1 13.2 12 13.6 11.8C14.1 11.6 14.5 11.3 14.7 11.1C14.9 10.9 15.2 10.6 15.5 10.3C15.8 10 15.9 9.80003 15.9 9.70003C15.9 9.60003 16.1 9.60004 16.3 9.60004C16.5 9.60004 16.7 9.70003 16.8 9.80003C16.9 9.90003 17 10.2 17 10.5V17.2C17 18 16.7 18.4 16.2 18.4C16 18.4 15.8 18.3 15.6 18.2C15.4 18.1 15.3 17.8 15.3 17.5Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
<input class="form-control form-control-solid ps-12" placeholder="Date"
|
||||
name="due_date" id="due_date" />
|
||||
</div>
|
||||
</div> --}}
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Subject</label>
|
||||
<input type="text" name="name" class="form-control mb-2 col-6"
|
||||
value="{{ old('name') }}" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Subject (EN)</label>
|
||||
<input type="text" name="name_en" class="form-control mb-2 col-6"
|
||||
value="{{ old('name_en') }}" />
|
||||
</div>
|
||||
|
||||
{{-- <div class="mb-10 fv-row">
|
||||
<label class="required form-label">Description</label>
|
||||
<div class="form-control" id="description" name="description"></div>
|
||||
<input type="hidden" id="description_input" name="description" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Description (EN)</label>
|
||||
<div class="form-control" id="description_en" name="description_en"></div>
|
||||
<input type="hidden" id="description_input_en" name="description_en" />
|
||||
|
||||
</div> --}}
|
||||
|
||||
{{-- <div hidden class="mb-10">
|
||||
<label class="form-label required">File Video</label>
|
||||
<input class="files-video" type="file" name="file_video[]" multiple
|
||||
accept=".MP4, .MOV">
|
||||
<div class="text-muted fs-7">Allowed Types .MP4, .MOV</div>
|
||||
</div>
|
||||
|
||||
<div hidden class="mb-10">
|
||||
<label class="form-label required">File Image</label>
|
||||
<input class="files-image" type="file" name="file_image[]" multiple
|
||||
accept=".jpg, .bmp, .jpeg, .png">
|
||||
<div class="text-muted fs-7">Allowed Types .jpg, .bmp, .jpeg, .png</div>
|
||||
</div>
|
||||
|
||||
<div hidden class="mb-10">
|
||||
<label class="form-label required">File Sound</label>
|
||||
<input class="files-sound" type="file" name="file_sound[]" multiple
|
||||
accept=".m4a, .mp4, .mp3, .wav">
|
||||
<div class="text-muted fs-7">Allowed Types .m4a, .mp4, .mp3, .wav</div>
|
||||
</div>
|
||||
|
||||
<div hidden class="mb-10">
|
||||
<label class="form-label required">File Documents</label>
|
||||
<input class="files-document" type="file" name="file_document[]" multiple
|
||||
accept=".pdf, .xls, .doc, .docx, .pptx, .csv, .txt">
|
||||
<div class="text-muted fs-7">Allowed Types .pdf, .xls, .doc, .docx, .pptx, .csv,
|
||||
.txt</div>
|
||||
</div> --}}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('where-else/sub-category') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button id="btn_submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save Changes</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<!-- Include Editor.js core -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest"></script>
|
||||
|
||||
<!-- Include the plugins -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/header"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/list"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/paragraph"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/quote"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/image"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/editorjs-inline-image"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/embed"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/code"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/table"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/marker"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/checklist"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/delimiter"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/warning"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/link"></script>
|
||||
|
||||
<script>
|
||||
/*
|
||||
class VideoTool {
|
||||
constructor({
|
||||
data
|
||||
}) {
|
||||
this.data = data || {};
|
||||
}
|
||||
|
||||
// Render input for video URL
|
||||
render() {
|
||||
const wrapper = document.createElement("div");
|
||||
|
||||
const input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.placeholder = "Enter video URL";
|
||||
input.value = this.data.url || "";
|
||||
input.style.width = "100%";
|
||||
|
||||
const video = document.createElement("video");
|
||||
video.controls = true;
|
||||
video.style.width = "100%";
|
||||
video.style.marginTop = "10px";
|
||||
video.src = this.data.url || "";
|
||||
|
||||
input.addEventListener("input", (event) => {
|
||||
const value = event.target.value;
|
||||
this.data.url = value;
|
||||
video.src = value;
|
||||
});
|
||||
|
||||
wrapper.appendChild(input);
|
||||
wrapper.appendChild(video);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
// Save the video URL
|
||||
save(blockContent) {
|
||||
const input = blockContent.querySelector("input");
|
||||
return {
|
||||
url: input.value,
|
||||
};
|
||||
}
|
||||
|
||||
// Editor.js toolbox definition
|
||||
static get toolbox() {
|
||||
return {
|
||||
title: "Video",
|
||||
icon: '<svg width="20" height="20" viewBox="0 0 24 24"><path d="M10 8.64L15.27 12 10 15.36V8.64M10 3.14L21 12 10 20.86V3.14M3 4h4v16H3V4z"></path></svg>',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const tools = {
|
||||
header: {
|
||||
class: Header,
|
||||
inlineToolbar: ['link', 'bold', 'italic'],
|
||||
config: {
|
||||
placeholder: 'Enter a header',
|
||||
levels: [2, 3, 4], // Set header levels
|
||||
defaultLevel: 3,
|
||||
},
|
||||
},
|
||||
embed: {
|
||||
class: Embed,
|
||||
inlineToolbar: true,
|
||||
config: {
|
||||
services: {
|
||||
youtube: true,
|
||||
vimeo: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
video: {
|
||||
class: VideoTool,
|
||||
inlineToolbar: true,
|
||||
},
|
||||
image: {
|
||||
class: InlineImage,
|
||||
inlineToolbar: true,
|
||||
config: {
|
||||
embed: {
|
||||
display: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const editorDescription = new EditorJS({
|
||||
holder: 'description',
|
||||
tools: tools
|
||||
});
|
||||
const editorDescriptionEn = new EditorJS({
|
||||
holder: 'description_en',
|
||||
tools: tools,
|
||||
});
|
||||
*/
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
/*
|
||||
$('#due_date').flatpickr({
|
||||
enableTime: false,
|
||||
dateFormat: 'd-m-Y',
|
||||
defaultDate: null, // Do not preselect any date
|
||||
onReady: function(selectedDates, dateStr, instance) {
|
||||
// Highlight today's date with a custom CSS class
|
||||
const today = instance.todayDateElem;
|
||||
today.classList.add('flatpickr-today-highlight'); // Add a custom class to today
|
||||
}
|
||||
});
|
||||
|
||||
// file video
|
||||
$('.files-video').fileuploader({
|
||||
extensions: ['MP4', 'mp4', 'MOV', 'mov'],
|
||||
limit: null,
|
||||
fileMaxSize: null,
|
||||
changeInput: '<div class="fileuploader-input">' +
|
||||
'<div class="fileuploader-input-inner">' +
|
||||
'<p><i class="fileuploader-icon-main"></i></p>' +
|
||||
'<h6>Drag and drop files here</h6>' +
|
||||
'<p>or</p>' +
|
||||
'<br>' +
|
||||
'<button type="button" class="fileuploader-input-button"><span>${captions.button}</span></button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
theme: 'dragdrop',
|
||||
});
|
||||
|
||||
// file image
|
||||
$('.files-image').fileuploader({
|
||||
extensions: ['jpg', 'bmp', 'jpeg', 'png'],
|
||||
limit: null,
|
||||
fileMaxSize: null,
|
||||
changeInput: '<div class="fileuploader-input">' +
|
||||
'<div class="fileuploader-input-inner">' +
|
||||
'<p><i class="fileuploader-icon-main"></i></p>' +
|
||||
'<h6>Drag and drop files here</h6>' +
|
||||
'<p>or</p>' +
|
||||
'<br>' +
|
||||
'<button type="button" class="fileuploader-input-button"><span>${captions.button}</span></button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
theme: 'dragdrop',
|
||||
});
|
||||
|
||||
// file sound
|
||||
$('.files-sound').fileuploader({
|
||||
extensions: ['m4a', 'mp4', 'mp3', 'wav'],
|
||||
limit: null,
|
||||
fileMaxSize: null,
|
||||
changeInput: '<div class="fileuploader-input">' +
|
||||
'<div class="fileuploader-input-inner">' +
|
||||
'<p><i class="fileuploader-icon-main"></i></p>' +
|
||||
'<h6>Drag and drop files here</h6>' +
|
||||
'<p>or</p>' +
|
||||
'<br>' +
|
||||
'<button type="button" class="fileuploader-input-button"><span>${captions.button}</span></button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
theme: 'dragdrop',
|
||||
});
|
||||
|
||||
// file document
|
||||
$('.files-document').fileuploader({
|
||||
extensions: ['pdf', 'xls', 'doc', 'docx', 'pptx', 'csv', 'txt'],
|
||||
limit: null,
|
||||
fileMaxSize: null,
|
||||
changeInput: '<div class="fileuploader-input">' +
|
||||
'<div class="fileuploader-input-inner">' +
|
||||
'<p><i class="fileuploader-icon-main"></i></p>' +
|
||||
'<h6>Drag and drop files here</h6>' +
|
||||
'<p>or</p>' +
|
||||
'<br>' +
|
||||
'<button type="button" class="fileuploader-input-button"><span>${captions.button}</span></button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
theme: 'dragdrop',
|
||||
});
|
||||
*/
|
||||
|
||||
$(document).on('click', '#btn_submit', function(e) {
|
||||
e.preventDefault(); // Prevent default form submission
|
||||
|
||||
alertLoading("Loading..."); // Show loading alert (your custom function)
|
||||
$('#frmAdd').submit();
|
||||
|
||||
/*
|
||||
// Save both editor contents
|
||||
Promise.all([editorDescription.save(), editorDescriptionEn.save()])
|
||||
.then(([descriptionData, descriptionEnData]) => {
|
||||
|
||||
// Store the JSON output in the hidden input fields
|
||||
$('#description_input').val(JSON.stringify(descriptionData));
|
||||
$('#description_input_en').val(JSON.stringify(descriptionEnData));
|
||||
|
||||
// Submit the form after saving the data
|
||||
$('#frmAdd').submit();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error saving editor content:', error);
|
||||
});
|
||||
*/
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,505 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<style>
|
||||
.video-responsive {
|
||||
position: relative;
|
||||
padding-bottom: 56.25%;
|
||||
/* Aspect ratio 16:9 */
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.video-responsive video {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'WHERE ELSE : Edit Sub Category',
|
||||
'pageName' => 'Edit',
|
||||
'pageParent' => 'Sub Category Management',
|
||||
'pageParentLink' => url('where-else/sub-category'),
|
||||
])
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
|
||||
<form id="frmUpdate" class="form d-flex flex-column flex-lg-row"
|
||||
action="{{ url('where-else/update-sub-category') }}" method="post" enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="id" value="{{ $itemView->id }}">
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
{{-- Left --}}
|
||||
<div class="d-flex flex-column gap-7 gap-lg-10 w-100 w-lg-300px mb-7 me-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
<div class="card-body text-center pt-0">
|
||||
|
||||
<style>
|
||||
.image-input-placeholder {
|
||||
background-image: url('{{ url('assets/media/svg/files/blank-image.svg') }}');
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .image-input-placeholder {
|
||||
background-image: url('../media/svg/files/blank-image-dark.svg');
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="image-input image-input-empty image-input-outline image-input-placeholder mb-3"
|
||||
data-kt-image-input="true">
|
||||
|
||||
|
||||
@if ($itemView->image_url && $itemView->image_name)
|
||||
<div class="image-input-wrapper w-150px h-150px"
|
||||
style="background-image: url('{{ $itemView->image_url . '/thumbnail/' . $itemView->image_name }}')">
|
||||
</div>
|
||||
@else
|
||||
<div class="image-input-wrapper w-150px h-150px"></div>
|
||||
@endif
|
||||
|
||||
<label
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="change" data-bs-toggle="tooltip"
|
||||
title="Change avatar">
|
||||
|
||||
<i class="bi bi-pencil-fill fs-7"></i>
|
||||
|
||||
<input type="file" name="avatar" accept=".png, .jpg, .jpeg" />
|
||||
<input type="hidden" name="avatar_remove" />
|
||||
|
||||
</label>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="cancel" data-bs-toggle="tooltip"
|
||||
title="Cancel avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="remove" data-bs-toggle="tooltip"
|
||||
title="Remove avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="text-muted fs-7">Set the profile picture. Only *.png, *.jpg and *.jpeg
|
||||
image
|
||||
files are accepted</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-header" style="border: unset;">
|
||||
<!--begin::Card title-->
|
||||
<div class="required card-title">
|
||||
<h2>Active</h2>
|
||||
</div>
|
||||
<!--end::Card title-->
|
||||
</div>
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<label class="form-check form-switch form-check-custom form-check-solid">
|
||||
<input class="form-check-input" name="active" type="checkbox" value="1"
|
||||
{{ $itemView->active == 1 ? 'checked' : '' }} />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{{-- Right --}}
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
{{-- <div class="mb-10 fv-row">
|
||||
<div class="position-relative d-flex align-items-center">
|
||||
<span class="svg-icon svg-icon-2 position-absolute mx-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21 22H3C2.4 22 2 21.6 2 21V5C2 4.4 2.4 4 3 4H21C21.6 4 22 4.4 22 5V21C22 21.6 21.6 22 21 22Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M6 6C5.4 6 5 5.6 5 5V3C5 2.4 5.4 2 6 2C6.6 2 7 2.4 7 3V5C7 5.6 6.6 6 6 6ZM11 5V3C11 2.4 10.6 2 10 2C9.4 2 9 2.4 9 3V5C9 5.6 9.4 6 10 6C10.6 6 11 5.6 11 5ZM15 5V3C15 2.4 14.6 2 14 2C13.4 2 13 2.4 13 3V5C13 5.6 13.4 6 14 6C14.6 6 15 5.6 15 5ZM19 5V3C19 2.4 18.6 2 18 2C17.4 2 17 2.4 17 3V5C17 5.6 17.4 6 18 6C18.6 6 19 5.6 19 5Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M8.8 13.1C9.2 13.1 9.5 13 9.7 12.8C9.9 12.6 10.1 12.3 10.1 11.9C10.1 11.6 10 11.3 9.8 11.1C9.6 10.9 9.3 10.8 9 10.8C8.8 10.8 8.59999 10.8 8.39999 10.9C8.19999 11 8.1 11.1 8 11.2C7.9 11.3 7.8 11.4 7.7 11.6C7.6 11.8 7.5 11.9 7.5 12.1C7.5 12.2 7.4 12.2 7.3 12.3C7.2 12.4 7.09999 12.4 6.89999 12.4C6.69999 12.4 6.6 12.3 6.5 12.2C6.4 12.1 6.3 11.9 6.3 11.7C6.3 11.5 6.4 11.3 6.5 11.1C6.6 10.9 6.8 10.7 7 10.5C7.2 10.3 7.49999 10.1 7.89999 10C8.29999 9.90003 8.60001 9.80003 9.10001 9.80003C9.50001 9.80003 9.80001 9.90003 10.1 10C10.4 10.1 10.7 10.3 10.9 10.4C11.1 10.5 11.3 10.8 11.4 11.1C11.5 11.4 11.6 11.6 11.6 11.9C11.6 12.3 11.5 12.6 11.3 12.9C11.1 13.2 10.9 13.5 10.6 13.7C10.9 13.9 11.2 14.1 11.4 14.3C11.6 14.5 11.8 14.7 11.9 15C12 15.3 12.1 15.5 12.1 15.8C12.1 16.2 12 16.5 11.9 16.8C11.8 17.1 11.5 17.4 11.3 17.7C11.1 18 10.7 18.2 10.3 18.3C9.9 18.4 9.5 18.5 9 18.5C8.5 18.5 8.1 18.4 7.7 18.2C7.3 18 7 17.8 6.8 17.6C6.6 17.4 6.4 17.1 6.3 16.8C6.2 16.5 6.10001 16.3 6.10001 16.1C6.10001 15.9 6.2 15.7 6.3 15.6C6.4 15.5 6.6 15.4 6.8 15.4C6.9 15.4 7.00001 15.4 7.10001 15.5C7.20001 15.6 7.3 15.6 7.3 15.7C7.5 16.2 7.7 16.6 8 16.9C8.3 17.2 8.6 17.3 9 17.3C9.2 17.3 9.5 17.2 9.7 17.1C9.9 17 10.1 16.8 10.3 16.6C10.5 16.4 10.5 16.1 10.5 15.8C10.5 15.3 10.4 15 10.1 14.7C9.80001 14.4 9.50001 14.3 9.10001 14.3C9.00001 14.3 8.9 14.3 8.7 14.3C8.5 14.3 8.39999 14.3 8.39999 14.3C8.19999 14.3 7.99999 14.2 7.89999 14.1C7.79999 14 7.7 13.8 7.7 13.7C7.7 13.5 7.79999 13.4 7.89999 13.2C7.99999 13 8.2 13 8.5 13H8.8V13.1ZM15.3 17.5V12.2C14.3 13 13.6 13.3 13.3 13.3C13.1 13.3 13 13.2 12.9 13.1C12.8 13 12.7 12.8 12.7 12.6C12.7 12.4 12.8 12.3 12.9 12.2C13 12.1 13.2 12 13.6 11.8C14.1 11.6 14.5 11.3 14.7 11.1C14.9 10.9 15.2 10.6 15.5 10.3C15.8 10 15.9 9.80003 15.9 9.70003C15.9 9.60003 16.1 9.60004 16.3 9.60004C16.5 9.60004 16.7 9.70003 16.8 9.80003C16.9 9.90003 17 10.2 17 10.5V17.2C17 18 16.7 18.4 16.2 18.4C16 18.4 15.8 18.3 15.6 18.2C15.4 18.1 15.3 17.8 15.3 17.5Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
<input class="form-control form-control-solid ps-12" type="text"
|
||||
id="due_date" name="due_date"
|
||||
value="{{ $itemView->due_date ? date('d-m-Y', strtotime($itemView->due_date)) : '' }}">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div> --}}
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Subject</label>
|
||||
<input type="text" name="name" class="form-control mb-2 col-6"
|
||||
value="{{ $itemView->name }}" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Subject (EN)</label>
|
||||
<input type="text" name="name_en" class="form-control mb-2 col-6"
|
||||
value="{{ $itemView->name_en }}" />
|
||||
</div>
|
||||
|
||||
{{-- <div class="mb-10 fv-row">
|
||||
<label class="required form-label">Description</label>
|
||||
<div class="form-control" id="description" name="description"></div>
|
||||
<input type="hidden" id="description_input" name="description" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Description (EN)</label>
|
||||
<div class="form-control" id="description_en" name="description_en"></div>
|
||||
<input type="hidden" id="description_input_en" name="description_en" />
|
||||
|
||||
</div> --}}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('where-else/sub-category') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button type="button" id="btn_submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
/*
|
||||
$('#due_date').flatpickr({
|
||||
enableTime: false,
|
||||
dateFormat: 'd-m-Y',
|
||||
defaultDate: null, // Do not preselect any date
|
||||
onReady: function(selectedDates, dateStr, instance) {
|
||||
// Highlight today's date with a custom CSS class
|
||||
const today = instance.todayDateElem;
|
||||
today.classList.add('flatpickr-today-highlight'); // Add a custom class to today
|
||||
}
|
||||
});
|
||||
|
||||
// file video
|
||||
$('.files-video').fileuploader({
|
||||
extensions: ['MP4', 'mp4', 'MOV', 'mov'],
|
||||
limit: null,
|
||||
fileMaxSize: null,
|
||||
changeInput: '<div class="fileuploader-input">' +
|
||||
'<div class="fileuploader-input-inner">' +
|
||||
'<p><i class="fileuploader-icon-main"></i></p>' +
|
||||
'<h6>Drag and drop files here</h6>' +
|
||||
'<p>or</p>' +
|
||||
'<br>' +
|
||||
'<button type="button" class="fileuploader-input-button"><span>${captions.button}</span></button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
theme: 'dragdrop',
|
||||
});
|
||||
|
||||
// file image
|
||||
$('.files-image').fileuploader({
|
||||
extensions: ['jpg', 'bmp', 'jpeg', 'png'],
|
||||
limit: null,
|
||||
fileMaxSize: null,
|
||||
changeInput: '<div class="fileuploader-input">' +
|
||||
'<div class="fileuploader-input-inner">' +
|
||||
'<p><i class="fileuploader-icon-main"></i></p>' +
|
||||
'<h6>Drag and drop files here</h6>' +
|
||||
'<p>or</p>' +
|
||||
'<br>' +
|
||||
'<button type="button" class="fileuploader-input-button"><span>${captions.button}</span></button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
theme: 'dragdrop',
|
||||
});
|
||||
|
||||
// file sound
|
||||
$('.files-sound').fileuploader({
|
||||
extensions: ['m4a', 'mp4', 'mp3', 'wav'],
|
||||
limit: null,
|
||||
fileMaxSize: null,
|
||||
changeInput: '<div class="fileuploader-input">' +
|
||||
'<div class="fileuploader-input-inner">' +
|
||||
'<p><i class="fileuploader-icon-main"></i></p>' +
|
||||
'<h6>Drag and drop files here</h6>' +
|
||||
'<p>or</p>' +
|
||||
'<br>' +
|
||||
'<button type="button" class="fileuploader-input-button"><span>${captions.button}</span></button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
theme: 'dragdrop',
|
||||
});
|
||||
|
||||
// file document
|
||||
$('.files-document').fileuploader({
|
||||
extensions: ['pdf', 'xls', 'doc', 'docx', 'pptx', 'csv', 'txt'],
|
||||
limit: null,
|
||||
fileMaxSize: null,
|
||||
changeInput: '<div class="fileuploader-input">' +
|
||||
'<div class="fileuploader-input-inner">' +
|
||||
'<p><i class="fileuploader-icon-main"></i></p>' +
|
||||
'<h6>Drag and drop files here</h6>' +
|
||||
'<p>or</p>' +
|
||||
'<br>' +
|
||||
'<button type="button" class="fileuploader-input-button"><span>${captions.button}</span></button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
theme: 'dragdrop',
|
||||
});
|
||||
*/
|
||||
|
||||
$(document).on("click", "#btn_submit", function(e) {
|
||||
e.preventDefault();
|
||||
alertLoading("Loading")
|
||||
const form = $('#frmUpdate');
|
||||
form.submit();
|
||||
})
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
{{-- <!-- Include Editor.js core -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest"></script>
|
||||
|
||||
<!-- Include the plugins -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/header"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/list"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/paragraph"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/quote"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/image"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/editorjs-inline-image"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/embed"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/code"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/table"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/marker"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/checklist"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/delimiter"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/warning"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/link"></script> --}}
|
||||
|
||||
<script>
|
||||
/*
|
||||
// Custom video tool for embedding videos
|
||||
class VideoTool {
|
||||
constructor({
|
||||
data
|
||||
}) {
|
||||
this.data = data || {};
|
||||
}
|
||||
|
||||
// Render input for video URL
|
||||
render() {
|
||||
const wrapper = document.createElement("div");
|
||||
|
||||
const input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.placeholder = "Enter video URL";
|
||||
input.value = this.data.url || "";
|
||||
input.style.width = "100%";
|
||||
|
||||
const video = document.createElement("video");
|
||||
video.controls = true;
|
||||
video.style.width = "100%";
|
||||
video.style.marginTop = "10px";
|
||||
video.src = this.data.url || "";
|
||||
|
||||
input.addEventListener("input", (event) => {
|
||||
const value = event.target.value;
|
||||
this.data.url = value;
|
||||
video.src = value;
|
||||
});
|
||||
|
||||
wrapper.appendChild(input);
|
||||
wrapper.appendChild(video);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
// Save the video URL
|
||||
save(blockContent) {
|
||||
const input = blockContent.querySelector("input");
|
||||
return {
|
||||
url: input.value,
|
||||
};
|
||||
}
|
||||
|
||||
// Editor.js toolbox definition
|
||||
static get toolbox() {
|
||||
return {
|
||||
title: "Video",
|
||||
icon: '<svg width="20" height="20" viewBox="0 0 24 24"><path d="M10 8.64L15.27 12 10 15.36V8.64M10 3.14L21 12 10 20.86V3.14M3 4h4v16H3V4z"></path></svg>',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const tools = {
|
||||
header: {
|
||||
class: Header,
|
||||
inlineToolbar: ['link', 'bold', 'italic'],
|
||||
config: {
|
||||
placeholder: 'Enter a header',
|
||||
levels: [2, 3, 4], // Set header levels
|
||||
defaultLevel: 3,
|
||||
},
|
||||
},
|
||||
embed: {
|
||||
class: Embed,
|
||||
inlineToolbar: true,
|
||||
config: {
|
||||
services: {
|
||||
youtube: true,
|
||||
vimeo: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
video: {
|
||||
class: VideoTool,
|
||||
inlineToolbar: true,
|
||||
},
|
||||
image: {
|
||||
class: InlineImage,
|
||||
inlineToolbar: true,
|
||||
config: {
|
||||
embed: {
|
||||
display: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const descriptionData = {!! json_encode($itemView->description) !!};
|
||||
const editorDescription = new EditorJS({
|
||||
holder: 'description',
|
||||
tools: tools,
|
||||
data: descriptionData != "" ? JSON.parse(descriptionData) : {},
|
||||
onChange: () => {
|
||||
saveData(editorDescription, 'description_input')
|
||||
}
|
||||
});
|
||||
|
||||
const descriptionDataEn = {!! json_encode($itemView->description_en) !!};
|
||||
const editorDescriptionEn = new EditorJS({
|
||||
holder: 'description_en',
|
||||
tools: tools,
|
||||
data: descriptionDataEn !== "" ? JSON.parse(descriptionDataEn) : {},
|
||||
onChange: () => {
|
||||
saveData(editorDescriptionEn, 'description_input_en');
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
|
||||
// Function to save data to hidden inputs
|
||||
function saveData(editor, inputId) {
|
||||
editor.save().then((outputData) => {
|
||||
document.getElementById(inputId).value = JSON.stringify(outputData);
|
||||
}).catch((error) => {
|
||||
console.error('Saving failed: ', error);
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '#btn_submit', function(e) {
|
||||
e.preventDefault(); // Prevent default form submission
|
||||
|
||||
alertLoading("Loading..."); // Show loading alert (your custom function)
|
||||
$('#frmUpdate').submit();
|
||||
|
||||
/*
|
||||
// Save both editor contents
|
||||
Promise.all([editorDescription.save(), editorDescriptionEn.save()])
|
||||
.then(([descriptionData, descriptionEnData]) => {
|
||||
// Store the JSON output in the hidden input fields
|
||||
$('#description_input').val(JSON.stringify(descriptionData));
|
||||
$('#description_input_en').val(JSON.stringify(descriptionEnData));
|
||||
|
||||
// Submit the form after saving the data
|
||||
$('#frmUpdate').submit();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error saving editor content:', error);
|
||||
});
|
||||
*/
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,408 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.breadcrumbList', [
|
||||
'title' => 'WHERE ELSE : Sub Category Management',
|
||||
'pageName' => 'Sub Category Management',
|
||||
])
|
||||
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<!--begin::Content container-->
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
<!--begin::Card-->
|
||||
<div class="card">
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<!--begin::Card header-->
|
||||
<div class="card-header border-0 pt-6">
|
||||
<!--begin::Card title-->
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
</div>
|
||||
|
||||
|
||||
@if (Auth::user()->role != 2)
|
||||
<div class="card-toolbar">
|
||||
<div class="d-flex justify-content-end" data-kt-customer-table-toolbar="base">
|
||||
<a href="{{ url('where-else/add-sub-category') }}" class="btn btn-primary">Add
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card-header border-0 pt-5">
|
||||
|
||||
<div class="card-title">
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
<span class="svg-icon svg-icon-1 position-absolute ms-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<rect opacity="0.5" x="17.0365" y="15.1223" width="8.15546" height="2"
|
||||
rx="1" transform="rotate(45 17.0365 15.1223)" fill="currentColor">
|
||||
</rect>
|
||||
<path
|
||||
d="M11 19C6.55556 19 3 15.4444 3 11C3 6.55556 6.55556 3 11 3C15.4444 3 19 6.55556 19 11C19 15.4444 15.4444 19 11 19ZM11 5C7.53333 5 5 7.53333 5 11C5 14.4667 7.53333 17 11 17C14.4667 17 17 14.4667 17 11C17 7.53333 14.4667 5 11 5Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<input type="text" table-filter="search"
|
||||
class="form-control form-control-solid w-250px ps-15" placeholder="Search" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- <div class="card-toolbar flex-row-fluid justify-content-end gap-5">
|
||||
|
||||
<div class="w-100 mw-150px">
|
||||
<div class="position-relative d-flex align-items-center">
|
||||
<span class="svg-icon svg-icon-2 position-absolute mx-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21 22H3C2.4 22 2 21.6 2 21V5C2 4.4 2.4 4 3 4H21C21.6 4 22 4.4 22 5V21C22 21.6 21.6 22 21 22Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M6 6C5.4 6 5 5.6 5 5V3C5 2.4 5.4 2 6 2C6.6 2 7 2.4 7 3V5C7 5.6 6.6 6 6 6ZM11 5V3C11 2.4 10.6 2 10 2C9.4 2 9 2.4 9 3V5C9 5.6 9.4 6 10 6C10.6 6 11 5.6 11 5ZM15 5V3C15 2.4 14.6 2 14 2C13.4 2 13 2.4 13 3V5C13 5.6 13.4 6 14 6C14.6 6 15 5.6 15 5ZM19 5V3C19 2.4 18.6 2 18 2C17.4 2 17 2.4 17 3V5C17 5.6 17.4 6 18 6C18.6 6 19 5.6 19 5Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M8.8 13.1C9.2 13.1 9.5 13 9.7 12.8C9.9 12.6 10.1 12.3 10.1 11.9C10.1 11.6 10 11.3 9.8 11.1C9.6 10.9 9.3 10.8 9 10.8C8.8 10.8 8.59999 10.8 8.39999 10.9C8.19999 11 8.1 11.1 8 11.2C7.9 11.3 7.8 11.4 7.7 11.6C7.6 11.8 7.5 11.9 7.5 12.1C7.5 12.2 7.4 12.2 7.3 12.3C7.2 12.4 7.09999 12.4 6.89999 12.4C6.69999 12.4 6.6 12.3 6.5 12.2C6.4 12.1 6.3 11.9 6.3 11.7C6.3 11.5 6.4 11.3 6.5 11.1C6.6 10.9 6.8 10.7 7 10.5C7.2 10.3 7.49999 10.1 7.89999 10C8.29999 9.90003 8.60001 9.80003 9.10001 9.80003C9.50001 9.80003 9.80001 9.90003 10.1 10C10.4 10.1 10.7 10.3 10.9 10.4C11.1 10.5 11.3 10.8 11.4 11.1C11.5 11.4 11.6 11.6 11.6 11.9C11.6 12.3 11.5 12.6 11.3 12.9C11.1 13.2 10.9 13.5 10.6 13.7C10.9 13.9 11.2 14.1 11.4 14.3C11.6 14.5 11.8 14.7 11.9 15C12 15.3 12.1 15.5 12.1 15.8C12.1 16.2 12 16.5 11.9 16.8C11.8 17.1 11.5 17.4 11.3 17.7C11.1 18 10.7 18.2 10.3 18.3C9.9 18.4 9.5 18.5 9 18.5C8.5 18.5 8.1 18.4 7.7 18.2C7.3 18 7 17.8 6.8 17.6C6.6 17.4 6.4 17.1 6.3 16.8C6.2 16.5 6.10001 16.3 6.10001 16.1C6.10001 15.9 6.2 15.7 6.3 15.6C6.4 15.5 6.6 15.4 6.8 15.4C6.9 15.4 7.00001 15.4 7.10001 15.5C7.20001 15.6 7.3 15.6 7.3 15.7C7.5 16.2 7.7 16.6 8 16.9C8.3 17.2 8.6 17.3 9 17.3C9.2 17.3 9.5 17.2 9.7 17.1C9.9 17 10.1 16.8 10.3 16.6C10.5 16.4 10.5 16.1 10.5 15.8C10.5 15.3 10.4 15 10.1 14.7C9.80001 14.4 9.50001 14.3 9.10001 14.3C9.00001 14.3 8.9 14.3 8.7 14.3C8.5 14.3 8.39999 14.3 8.39999 14.3C8.19999 14.3 7.99999 14.2 7.89999 14.1C7.79999 14 7.7 13.8 7.7 13.7C7.7 13.5 7.79999 13.4 7.89999 13.2C7.99999 13 8.2 13 8.5 13H8.8V13.1ZM15.3 17.5V12.2C14.3 13 13.6 13.3 13.3 13.3C13.1 13.3 13 13.2 12.9 13.1C12.8 13 12.7 12.8 12.7 12.6C12.7 12.4 12.8 12.3 12.9 12.2C13 12.1 13.2 12 13.6 11.8C14.1 11.6 14.5 11.3 14.7 11.1C14.9 10.9 15.2 10.6 15.5 10.3C15.8 10 15.9 9.80003 15.9 9.70003C15.9 9.60003 16.1 9.60004 16.3 9.60004C16.5 9.60004 16.7 9.70003 16.8 9.80003C16.9 9.90003 17 10.2 17 10.5V17.2C17 18 16.7 18.4 16.2 18.4C16 18.4 15.8 18.3 15.6 18.2C15.4 18.1 15.3 17.8 15.3 17.5Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
<input class="form-control form-control-solid ps-12" placeholder="From"
|
||||
id="due_date_from" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="w-100 mw-150px">
|
||||
<div class="position-relative d-flex align-items-center">
|
||||
<span class="svg-icon svg-icon-2 position-absolute mx-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21 22H3C2.4 22 2 21.6 2 21V5C2 4.4 2.4 4 3 4H21C21.6 4 22 4.4 22 5V21C22 21.6 21.6 22 21 22Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M6 6C5.4 6 5 5.6 5 5V3C5 2.4 5.4 2 6 2C6.6 2 7 2.4 7 3V5C7 5.6 6.6 6 6 6ZM11 5V3C11 2.4 10.6 2 10 2C9.4 2 9 2.4 9 3V5C9 5.6 9.4 6 10 6C10.6 6 11 5.6 11 5ZM15 5V3C15 2.4 14.6 2 14 2C13.4 2 13 2.4 13 3V5C13 5.6 13.4 6 14 6C14.6 6 15 5.6 15 5ZM19 5V3C19 2.4 18.6 2 18 2C17.4 2 17 2.4 17 3V5C17 5.6 17.4 6 18 6C18.6 6 19 5.6 19 5Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M8.8 13.1C9.2 13.1 9.5 13 9.7 12.8C9.9 12.6 10.1 12.3 10.1 11.9C10.1 11.6 10 11.3 9.8 11.1C9.6 10.9 9.3 10.8 9 10.8C8.8 10.8 8.59999 10.8 8.39999 10.9C8.19999 11 8.1 11.1 8 11.2C7.9 11.3 7.8 11.4 7.7 11.6C7.6 11.8 7.5 11.9 7.5 12.1C7.5 12.2 7.4 12.2 7.3 12.3C7.2 12.4 7.09999 12.4 6.89999 12.4C6.69999 12.4 6.6 12.3 6.5 12.2C6.4 12.1 6.3 11.9 6.3 11.7C6.3 11.5 6.4 11.3 6.5 11.1C6.6 10.9 6.8 10.7 7 10.5C7.2 10.3 7.49999 10.1 7.89999 10C8.29999 9.90003 8.60001 9.80003 9.10001 9.80003C9.50001 9.80003 9.80001 9.90003 10.1 10C10.4 10.1 10.7 10.3 10.9 10.4C11.1 10.5 11.3 10.8 11.4 11.1C11.5 11.4 11.6 11.6 11.6 11.9C11.6 12.3 11.5 12.6 11.3 12.9C11.1 13.2 10.9 13.5 10.6 13.7C10.9 13.9 11.2 14.1 11.4 14.3C11.6 14.5 11.8 14.7 11.9 15C12 15.3 12.1 15.5 12.1 15.8C12.1 16.2 12 16.5 11.9 16.8C11.8 17.1 11.5 17.4 11.3 17.7C11.1 18 10.7 18.2 10.3 18.3C9.9 18.4 9.5 18.5 9 18.5C8.5 18.5 8.1 18.4 7.7 18.2C7.3 18 7 17.8 6.8 17.6C6.6 17.4 6.4 17.1 6.3 16.8C6.2 16.5 6.10001 16.3 6.10001 16.1C6.10001 15.9 6.2 15.7 6.3 15.6C6.4 15.5 6.6 15.4 6.8 15.4C6.9 15.4 7.00001 15.4 7.10001 15.5C7.20001 15.6 7.3 15.6 7.3 15.7C7.5 16.2 7.7 16.6 8 16.9C8.3 17.2 8.6 17.3 9 17.3C9.2 17.3 9.5 17.2 9.7 17.1C9.9 17 10.1 16.8 10.3 16.6C10.5 16.4 10.5 16.1 10.5 15.8C10.5 15.3 10.4 15 10.1 14.7C9.80001 14.4 9.50001 14.3 9.10001 14.3C9.00001 14.3 8.9 14.3 8.7 14.3C8.5 14.3 8.39999 14.3 8.39999 14.3C8.19999 14.3 7.99999 14.2 7.89999 14.1C7.79999 14 7.7 13.8 7.7 13.7C7.7 13.5 7.79999 13.4 7.89999 13.2C7.99999 13 8.2 13 8.5 13H8.8V13.1ZM15.3 17.5V12.2C14.3 13 13.6 13.3 13.3 13.3C13.1 13.3 13 13.2 12.9 13.1C12.8 13 12.7 12.8 12.7 12.6C12.7 12.4 12.8 12.3 12.9 12.2C13 12.1 13.2 12 13.6 11.8C14.1 11.6 14.5 11.3 14.7 11.1C14.9 10.9 15.2 10.6 15.5 10.3C15.8 10 15.9 9.80003 15.9 9.70003C15.9 9.60003 16.1 9.60004 16.3 9.60004C16.5 9.60004 16.7 9.70003 16.8 9.80003C16.9 9.90003 17 10.2 17 10.5V17.2C17 18 16.7 18.4 16.2 18.4C16 18.4 15.8 18.3 15.6 18.2C15.4 18.1 15.3 17.8 15.3 17.5Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
<input class="form-control form-control-solid ps-12" placeholder="To"
|
||||
id="due_date_to" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="button" id="btn-submit" class="btn btn-primary">
|
||||
Search
|
||||
</button>
|
||||
|
||||
</div> --}}
|
||||
</div>
|
||||
|
||||
<div class="card-body py-4">
|
||||
<!--begin::Table-->
|
||||
<table class="table align-middle table-row-dashed fs-6 gy-5" id="data-table-category">
|
||||
<!--begin::Table head-->
|
||||
<thead>
|
||||
<!--begin::Table row-->
|
||||
<tr class="text-start text-muted fw-bold fs-7 text-uppercase gs-0">
|
||||
<th class="min-w-125px">Pic</th>
|
||||
{{-- <th class="min-w-125px">Date</th> --}}
|
||||
<th class="min-w-125px">Subject</th>
|
||||
<th class="min-w-125px">Subject (EN)</th>
|
||||
<th class="min-w-125px">Created</th>
|
||||
<th class="min-w-125px">Active</th>
|
||||
<th class="text-end min-w-100px">Manage</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="text-gray-600 fw-semibold">
|
||||
|
||||
@foreach ($itemView as $obj)
|
||||
<tr>
|
||||
<td class="d-flex align-items-center">
|
||||
<div class="symbol symbol-100px symbol-2by3 me-4">
|
||||
@if ($obj->image_url && $obj->image_name)
|
||||
<a class="show-image-preview d-block overlay"
|
||||
href="{{ url($obj->image_url . '/original/' . $obj->image_name) }}">
|
||||
<div class="symbol-label"
|
||||
style="background-image: url('{{ url($obj->image_url . '/thumbnail/' . $obj->image_name) }}')">
|
||||
</div>
|
||||
</a>
|
||||
@else
|
||||
<div class="symbol-label"
|
||||
style="background-image: url('{{ url('assets/media/avatars/blank.png') }}')">
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<a href="#" class="text-gray-800 text-hover-primary mb-1">
|
||||
{{ $obj->name }}
|
||||
</a>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<a href="#" class="text-gray-800 text-hover-primary mb-1">
|
||||
{{ $obj->name_en }}
|
||||
</a>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ Carbon\Carbon::parse($obj->created_at)->format('d, M Y') }}
|
||||
</td>
|
||||
|
||||
|
||||
<td>
|
||||
@if ($obj->active == 1)
|
||||
<span class="badge py-3 px-4 fs-7 badge-light-success">Active</span>
|
||||
@else
|
||||
<span class="badge py-3 px-4 fs-7 badge-light-danger">Inactive</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
||||
<td class="min-w-100px text-end">
|
||||
|
||||
{{-- View --}}
|
||||
<a href="{{ url('where-else/article/' . $obj->id) }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm me-1">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M17.5 11H6.5C4 11 2 9 2 6.5C2 4 4 2 6.5 2H17.5C20 2 22 4 22 6.5C22 9 20 11 17.5 11ZM15 6.5C15 7.9 16.1 9 17.5 9C18.9 9 20 7.9 20 6.5C20 5.1 18.9 4 17.5 4C16.1 4 15 5.1 15 6.5Z"
|
||||
fill="currentColor"></path>
|
||||
<path opacity="0.3"
|
||||
d="M17.5 22H6.5C4 22 2 20 2 17.5C2 15 4 13 6.5 13H17.5C20 13 22 15 22 17.5C22 20 20 22 17.5 22ZM4 17.5C4 18.9 5.1 20 6.5 20C7.9 20 9 18.9 9 17.5C9 16.1 7.9 15 6.5 15C5.1 15 4 16.1 4 17.5Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{{-- Edit --}}
|
||||
<a href="{{ url('where-else/edit-sub-category/' . $obj->id) }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm me-1">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21.4 8.35303L19.241 10.511L13.485 4.755L15.643 2.59595C16.0248 2.21423 16.5426 1.99988 17.0825 1.99988C17.6224 1.99988 18.1402 2.21423 18.522 2.59595L21.4 5.474C21.7817 5.85581 21.9962 6.37355 21.9962 6.91345C21.9962 7.45335 21.7817 7.97122 21.4 8.35303ZM3.68699 21.932L9.88699 19.865L4.13099 14.109L2.06399 20.309C1.98815 20.5354 1.97703 20.7787 2.03189 21.0111C2.08674 21.2436 2.2054 21.4561 2.37449 21.6248C2.54359 21.7934 2.75641 21.9115 2.989 21.9658C3.22158 22.0201 3.4647 22.0084 3.69099 21.932H3.68699Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M5.574 21.3L3.692 21.928C3.46591 22.0032 3.22334 22.0141 2.99144 21.9594C2.75954 21.9046 2.54744 21.7864 2.3789 21.6179C2.21036 21.4495 2.09202 21.2375 2.03711 21.0056C1.9822 20.7737 1.99289 20.5312 2.06799 20.3051L2.696 18.422L5.574 21.3ZM4.13499 14.105L9.891 19.861L19.245 10.507L13.489 4.75098L4.13499 14.105Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{{-- Delete --}}
|
||||
@if ($obj->active == 1 && Auth::user()->role != 2)
|
||||
<a href="#" data-id="{{ $obj->id }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm delete-item">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5 9C5 8.44772 5.44772 8 6 8H18C18.5523 8 19 8.44772 19 9V18C19 19.6569 17.6569 21 16 21H8C6.34315 21 5 19.6569 5 18V9Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M5 5C5 4.44772 5.44772 4 6 4H18C18.5523 4 19 4.44772 19 5V5C19 5.55228 18.5523 6 18 6H6C5.44772 6 5 5.55228 5 5V5Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M9 4C9 3.44772 9.44772 3 10 3H14C14.5523 3 15 3.44772 15 4V4H9V4Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
const baseUrl = "{{ url('where-else/sub-category') }}";
|
||||
var datatable;
|
||||
datatable = $("#data-table-category").DataTable({
|
||||
"info": false,
|
||||
"order": [],
|
||||
"pageLength": 25,
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, 500, 1000],
|
||||
[10, 25, 50, 100, 500, 1000]
|
||||
]
|
||||
});
|
||||
|
||||
// Filter by search
|
||||
const filterSearch = document.querySelector('[table-filter="search"]');
|
||||
filterSearch.addEventListener('keyup', function(e) {
|
||||
datatable.search(e.target.value).draw();
|
||||
});
|
||||
|
||||
// filter by status
|
||||
const filterStatus = document.querySelector('[table-filter="status"]');
|
||||
$(filterStatus).on('change', e => {
|
||||
let value = e.target.value;
|
||||
if (value === 'all') {
|
||||
value = '';
|
||||
}
|
||||
datatable.column(4).search(value).draw();
|
||||
});
|
||||
|
||||
|
||||
// Remove
|
||||
$(document).on('click', '.delete-item', function() {
|
||||
swal.fire({
|
||||
allowOutsideClick: false,
|
||||
text: "Are you sure you would like to Delete?",
|
||||
icon: "warning",
|
||||
buttonsStyling: false,
|
||||
showDenyButton: true,
|
||||
confirmButtonText: "Yes",
|
||||
denyButtonText: 'No',
|
||||
customClass: {
|
||||
confirmButton: "btn btn-primary",
|
||||
denyButton: "btn btn-light-danger"
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
// set up ajax
|
||||
initAjaxSetupToken();
|
||||
|
||||
const ajaxProp = {
|
||||
url: "{{ url('where-else/delete-sub-category') }}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
item_id: $(this).data('id')
|
||||
},
|
||||
};
|
||||
|
||||
$.ajax(ajaxProp).done(function(res) {
|
||||
if (res.status) {
|
||||
const url = "{{ url('where-else/sub-category') }}";
|
||||
alertSuccessWithUrl('Notice', "Delete success", url);
|
||||
hideLoading();
|
||||
} else {
|
||||
alertFail('Notice', res.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
logAjaxError(xhr, status, error);
|
||||
alertFail('Notice', error.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
var today = new Date();
|
||||
var dateFormat = "d-m-Y";
|
||||
|
||||
var dueDateFrom = $("#due_date_from");
|
||||
var dueDateTo = $("#due_date_to");
|
||||
|
||||
const dateFrom = "{{ $fromDateView }}";
|
||||
const dateTo = "{{ $toDateView }}";
|
||||
|
||||
dueDateFrom.flatpickr({
|
||||
showClearButton: true,
|
||||
enableTime: false,
|
||||
dateFormat: dateFormat,
|
||||
maxDate: today,
|
||||
defaultDate: dateFrom,
|
||||
|
||||
});
|
||||
|
||||
dueDateTo.flatpickr({
|
||||
showClearButton: true,
|
||||
enableTime: false,
|
||||
dateFormat: dateFormat,
|
||||
maxDate: today,
|
||||
defaultDate: dateTo,
|
||||
|
||||
});
|
||||
|
||||
const clearDatePicker = () => {
|
||||
dueDateFrom.flatpickr().clear();
|
||||
dueDateTo.flatpickr().clear();
|
||||
|
||||
// Set the date format again after clearing
|
||||
dueDateFrom.flatpickr({
|
||||
dateFormat: dateFormat
|
||||
});
|
||||
dueDateTo.flatpickr({
|
||||
dateFormat: dateFormat
|
||||
});
|
||||
}
|
||||
|
||||
$('#btn-submit').on('click', (e) => {
|
||||
e.preventDefault(); // Prevent the default behavior of the anchor element
|
||||
|
||||
// from
|
||||
const fromDateSelected = $("#due_date_from").val();
|
||||
|
||||
// to
|
||||
const toDateSelected = $("#due_date_to").val();
|
||||
|
||||
if (fromDateSelected && toDateSelected) {
|
||||
var newUrl =
|
||||
`${baseUrl}/${fromDateSelected}/${toDateSelected}`;
|
||||
window.location.href = newUrl;
|
||||
} else {
|
||||
var newUrl = `${baseUrl}/all/all/`;
|
||||
window.location.href = newUrl;
|
||||
}
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,474 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'CHIANG MAI AND NOWHERE ELSE : Add Category Management',
|
||||
'pageName' => 'Add',
|
||||
'pageParent' => 'Sub Category Management',
|
||||
'pageParentLink' => url('no-where-else/sub-category'),
|
||||
])
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
|
||||
|
||||
<form id="frmAdd" class="form d-flex flex-column flex-lg-row"
|
||||
action="{{ url('no-where-else/insert-sub-category') }}" method="post"
|
||||
enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
<div class="d-flex flex-column gap-7 gap-lg-10 w-100 w-lg-300px mb-7 me-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
<div class="card-body text-center pt-0">
|
||||
|
||||
<style>
|
||||
.image-input-placeholder {
|
||||
background-image: url('{{ url('assets/media/svg/files/blank-image.svg') }}');
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .image-input-placeholder {
|
||||
background-image: url('../media/svg/files/blank-image-dark.svg');
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="image-input image-input-empty image-input-outline image-input-placeholder mb-3"
|
||||
data-kt-image-input="true">
|
||||
|
||||
<div class="image-input-wrapper w-150px h-150px"></div>
|
||||
|
||||
<label
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="change" data-bs-toggle="tooltip"
|
||||
title="Change avatar">
|
||||
|
||||
<i class="bi bi-pencil-fill fs-7"></i>
|
||||
|
||||
<input type="file" name="avatar" accept=".png, .jpg, .jpeg" />
|
||||
<input type="hidden" name="avatar_remove" />
|
||||
|
||||
</label>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="cancel" data-bs-toggle="tooltip"
|
||||
title="Cancel avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="remove" data-bs-toggle="tooltip"
|
||||
title="Remove avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="text-muted fs-7">Set the profile picture. Only *.png, *.jpg and *.jpeg
|
||||
image
|
||||
files are accepted</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{-- Active --}}
|
||||
<div class="card-header" style="border: unset;">
|
||||
<div class="required card-title">
|
||||
<h2>Active</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<label class="form-check form-switch form-check-custom form-check-solid">
|
||||
<input class="form-check-input" disabled readonly name="active" type="checkbox"
|
||||
value="1" checked />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
|
||||
{{-- <div class="mb-10 fv-row">
|
||||
<label class="required form-label">Date</label>
|
||||
<div class="position-relative d-flex align-items-center">
|
||||
<span class="svg-icon svg-icon-2 position-absolute mx-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21 22H3C2.4 22 2 21.6 2 21V5C2 4.4 2.4 4 3 4H21C21.6 4 22 4.4 22 5V21C22 21.6 21.6 22 21 22Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M6 6C5.4 6 5 5.6 5 5V3C5 2.4 5.4 2 6 2C6.6 2 7 2.4 7 3V5C7 5.6 6.6 6 6 6ZM11 5V3C11 2.4 10.6 2 10 2C9.4 2 9 2.4 9 3V5C9 5.6 9.4 6 10 6C10.6 6 11 5.6 11 5ZM15 5V3C15 2.4 14.6 2 14 2C13.4 2 13 2.4 13 3V5C13 5.6 13.4 6 14 6C14.6 6 15 5.6 15 5ZM19 5V3C19 2.4 18.6 2 18 2C17.4 2 17 2.4 17 3V5C17 5.6 17.4 6 18 6C18.6 6 19 5.6 19 5Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M8.8 13.1C9.2 13.1 9.5 13 9.7 12.8C9.9 12.6 10.1 12.3 10.1 11.9C10.1 11.6 10 11.3 9.8 11.1C9.6 10.9 9.3 10.8 9 10.8C8.8 10.8 8.59999 10.8 8.39999 10.9C8.19999 11 8.1 11.1 8 11.2C7.9 11.3 7.8 11.4 7.7 11.6C7.6 11.8 7.5 11.9 7.5 12.1C7.5 12.2 7.4 12.2 7.3 12.3C7.2 12.4 7.09999 12.4 6.89999 12.4C6.69999 12.4 6.6 12.3 6.5 12.2C6.4 12.1 6.3 11.9 6.3 11.7C6.3 11.5 6.4 11.3 6.5 11.1C6.6 10.9 6.8 10.7 7 10.5C7.2 10.3 7.49999 10.1 7.89999 10C8.29999 9.90003 8.60001 9.80003 9.10001 9.80003C9.50001 9.80003 9.80001 9.90003 10.1 10C10.4 10.1 10.7 10.3 10.9 10.4C11.1 10.5 11.3 10.8 11.4 11.1C11.5 11.4 11.6 11.6 11.6 11.9C11.6 12.3 11.5 12.6 11.3 12.9C11.1 13.2 10.9 13.5 10.6 13.7C10.9 13.9 11.2 14.1 11.4 14.3C11.6 14.5 11.8 14.7 11.9 15C12 15.3 12.1 15.5 12.1 15.8C12.1 16.2 12 16.5 11.9 16.8C11.8 17.1 11.5 17.4 11.3 17.7C11.1 18 10.7 18.2 10.3 18.3C9.9 18.4 9.5 18.5 9 18.5C8.5 18.5 8.1 18.4 7.7 18.2C7.3 18 7 17.8 6.8 17.6C6.6 17.4 6.4 17.1 6.3 16.8C6.2 16.5 6.10001 16.3 6.10001 16.1C6.10001 15.9 6.2 15.7 6.3 15.6C6.4 15.5 6.6 15.4 6.8 15.4C6.9 15.4 7.00001 15.4 7.10001 15.5C7.20001 15.6 7.3 15.6 7.3 15.7C7.5 16.2 7.7 16.6 8 16.9C8.3 17.2 8.6 17.3 9 17.3C9.2 17.3 9.5 17.2 9.7 17.1C9.9 17 10.1 16.8 10.3 16.6C10.5 16.4 10.5 16.1 10.5 15.8C10.5 15.3 10.4 15 10.1 14.7C9.80001 14.4 9.50001 14.3 9.10001 14.3C9.00001 14.3 8.9 14.3 8.7 14.3C8.5 14.3 8.39999 14.3 8.39999 14.3C8.19999 14.3 7.99999 14.2 7.89999 14.1C7.79999 14 7.7 13.8 7.7 13.7C7.7 13.5 7.79999 13.4 7.89999 13.2C7.99999 13 8.2 13 8.5 13H8.8V13.1ZM15.3 17.5V12.2C14.3 13 13.6 13.3 13.3 13.3C13.1 13.3 13 13.2 12.9 13.1C12.8 13 12.7 12.8 12.7 12.6C12.7 12.4 12.8 12.3 12.9 12.2C13 12.1 13.2 12 13.6 11.8C14.1 11.6 14.5 11.3 14.7 11.1C14.9 10.9 15.2 10.6 15.5 10.3C15.8 10 15.9 9.80003 15.9 9.70003C15.9 9.60003 16.1 9.60004 16.3 9.60004C16.5 9.60004 16.7 9.70003 16.8 9.80003C16.9 9.90003 17 10.2 17 10.5V17.2C17 18 16.7 18.4 16.2 18.4C16 18.4 15.8 18.3 15.6 18.2C15.4 18.1 15.3 17.8 15.3 17.5Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
<input class="form-control form-control-solid ps-12" placeholder="Date"
|
||||
name="due_date" id="due_date" />
|
||||
</div>
|
||||
</div> --}}
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Subject</label>
|
||||
<input type="text" name="name" class="form-control mb-2 col-6"
|
||||
value="{{ old('name') }}" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Subject (EN)</label>
|
||||
<input type="text" name="name_en" class="form-control mb-2 col-6"
|
||||
value="{{ old('name_en') }}" />
|
||||
</div>
|
||||
|
||||
{{-- <div class="mb-10 fv-row">
|
||||
<label class="required form-label">Description</label>
|
||||
<div class="form-control" id="description" name="description"></div>
|
||||
<input type="hidden" id="description_input" name="description" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Description (EN)</label>
|
||||
<div class="form-control" id="description_en" name="description_en"></div>
|
||||
<input type="hidden" id="description_input_en" name="description_en" />
|
||||
|
||||
</div> --}}
|
||||
|
||||
{{-- <div hidden class="mb-10">
|
||||
<label class="form-label required">File Video</label>
|
||||
<input class="files-video" type="file" name="file_video[]" multiple
|
||||
accept=".MP4, .MOV">
|
||||
<div class="text-muted fs-7">Allowed Types .MP4, .MOV</div>
|
||||
</div>
|
||||
|
||||
<div hidden class="mb-10">
|
||||
<label class="form-label required">File Image</label>
|
||||
<input class="files-image" type="file" name="file_image[]" multiple
|
||||
accept=".jpg, .bmp, .jpeg, .png">
|
||||
<div class="text-muted fs-7">Allowed Types .jpg, .bmp, .jpeg, .png</div>
|
||||
</div>
|
||||
|
||||
<div hidden class="mb-10">
|
||||
<label class="form-label required">File Sound</label>
|
||||
<input class="files-sound" type="file" name="file_sound[]" multiple
|
||||
accept=".m4a, .mp4, .mp3, .wav">
|
||||
<div class="text-muted fs-7">Allowed Types .m4a, .mp4, .mp3, .wav</div>
|
||||
</div>
|
||||
|
||||
<div hidden class="mb-10">
|
||||
<label class="form-label required">File Documents</label>
|
||||
<input class="files-document" type="file" name="file_document[]" multiple
|
||||
accept=".pdf, .xls, .doc, .docx, .pptx, .csv, .txt">
|
||||
<div class="text-muted fs-7">Allowed Types .pdf, .xls, .doc, .docx, .pptx, .csv,
|
||||
.txt</div>
|
||||
</div> --}}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('no-where-else/sub-category') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button id="btn_submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save Changes</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<!-- Include Editor.js core -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest"></script>
|
||||
|
||||
<!-- Include the plugins -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/header"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/list"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/paragraph"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/quote"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/image"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/editorjs-inline-image"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/embed"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/code"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/table"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/marker"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/checklist"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/delimiter"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/warning"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/link"></script>
|
||||
|
||||
|
||||
<script>
|
||||
/*
|
||||
class VideoTool {
|
||||
constructor({
|
||||
data
|
||||
}) {
|
||||
this.data = data || {};
|
||||
}
|
||||
|
||||
// Render input for video URL
|
||||
render() {
|
||||
const wrapper = document.createElement("div");
|
||||
|
||||
const input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.placeholder = "Enter video URL";
|
||||
input.value = this.data.url || "";
|
||||
input.style.width = "100%";
|
||||
|
||||
const video = document.createElement("video");
|
||||
video.controls = true;
|
||||
video.style.width = "100%";
|
||||
video.style.marginTop = "10px";
|
||||
video.src = this.data.url || "";
|
||||
|
||||
input.addEventListener("input", (event) => {
|
||||
const value = event.target.value;
|
||||
this.data.url = value;
|
||||
video.src = value;
|
||||
});
|
||||
|
||||
wrapper.appendChild(input);
|
||||
wrapper.appendChild(video);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
// Save the video URL
|
||||
save(blockContent) {
|
||||
const input = blockContent.querySelector("input");
|
||||
return {
|
||||
url: input.value,
|
||||
};
|
||||
}
|
||||
|
||||
// Editor.js toolbox definition
|
||||
static get toolbox() {
|
||||
return {
|
||||
title: "Video",
|
||||
icon: '<svg width="20" height="20" viewBox="0 0 24 24"><path d="M10 8.64L15.27 12 10 15.36V8.64M10 3.14L21 12 10 20.86V3.14M3 4h4v16H3V4z"></path></svg>',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const tools = {
|
||||
header: {
|
||||
class: Header,
|
||||
inlineToolbar: ['link', 'bold', 'italic'],
|
||||
config: {
|
||||
placeholder: 'Enter a header',
|
||||
levels: [2, 3, 4], // Set header levels
|
||||
defaultLevel: 3,
|
||||
},
|
||||
},
|
||||
embed: {
|
||||
class: Embed,
|
||||
inlineToolbar: true,
|
||||
config: {
|
||||
services: {
|
||||
youtube: true,
|
||||
vimeo: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
video: {
|
||||
class: VideoTool,
|
||||
inlineToolbar: true,
|
||||
},
|
||||
image: {
|
||||
class: InlineImage,
|
||||
inlineToolbar: true,
|
||||
config: {
|
||||
embed: {
|
||||
display: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
const editorDescription = new EditorJS({
|
||||
holder: 'description',
|
||||
tools: tools
|
||||
});
|
||||
const editorDescriptionEn = new EditorJS({
|
||||
holder: 'description_en',
|
||||
tools: tools,
|
||||
});
|
||||
*/
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
/*
|
||||
$('#due_date').flatpickr({
|
||||
enableTime: false,
|
||||
dateFormat: 'd-m-Y',
|
||||
defaultDate: null, // Do not preselect any date
|
||||
onReady: function(selectedDates, dateStr, instance) {
|
||||
// Highlight today's date with a custom CSS class
|
||||
const today = instance.todayDateElem;
|
||||
today.classList.add('flatpickr-today-highlight'); // Add a custom class to today
|
||||
}
|
||||
});
|
||||
|
||||
// file video
|
||||
$('.files-video').fileuploader({
|
||||
extensions: ['MP4', 'mp4', 'MOV', 'mov'],
|
||||
limit: null,
|
||||
fileMaxSize: null,
|
||||
changeInput: '<div class="fileuploader-input">' +
|
||||
'<div class="fileuploader-input-inner">' +
|
||||
'<p><i class="fileuploader-icon-main"></i></p>' +
|
||||
'<h6>Drag and drop files here</h6>' +
|
||||
'<p>or</p>' +
|
||||
'<br>' +
|
||||
'<button type="button" class="fileuploader-input-button"><span>${captions.button}</span></button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
theme: 'dragdrop',
|
||||
});
|
||||
|
||||
// file image
|
||||
$('.files-image').fileuploader({
|
||||
extensions: ['jpg', 'bmp', 'jpeg', 'png'],
|
||||
limit: null,
|
||||
fileMaxSize: null,
|
||||
changeInput: '<div class="fileuploader-input">' +
|
||||
'<div class="fileuploader-input-inner">' +
|
||||
'<p><i class="fileuploader-icon-main"></i></p>' +
|
||||
'<h6>Drag and drop files here</h6>' +
|
||||
'<p>or</p>' +
|
||||
'<br>' +
|
||||
'<button type="button" class="fileuploader-input-button"><span>${captions.button}</span></button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
theme: 'dragdrop',
|
||||
});
|
||||
|
||||
// file sound
|
||||
$('.files-sound').fileuploader({
|
||||
extensions: ['m4a', 'mp4', 'mp3', 'wav'],
|
||||
limit: null,
|
||||
fileMaxSize: null,
|
||||
changeInput: '<div class="fileuploader-input">' +
|
||||
'<div class="fileuploader-input-inner">' +
|
||||
'<p><i class="fileuploader-icon-main"></i></p>' +
|
||||
'<h6>Drag and drop files here</h6>' +
|
||||
'<p>or</p>' +
|
||||
'<br>' +
|
||||
'<button type="button" class="fileuploader-input-button"><span>${captions.button}</span></button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
theme: 'dragdrop',
|
||||
});
|
||||
|
||||
// file document
|
||||
$('.files-document').fileuploader({
|
||||
extensions: ['pdf', 'xls', 'doc', 'docx', 'pptx', 'csv', 'txt'],
|
||||
limit: null,
|
||||
fileMaxSize: null,
|
||||
changeInput: '<div class="fileuploader-input">' +
|
||||
'<div class="fileuploader-input-inner">' +
|
||||
'<p><i class="fileuploader-icon-main"></i></p>' +
|
||||
'<h6>Drag and drop files here</h6>' +
|
||||
'<p>or</p>' +
|
||||
'<br>' +
|
||||
'<button type="button" class="fileuploader-input-button"><span>${captions.button}</span></button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
theme: 'dragdrop',
|
||||
});
|
||||
*/
|
||||
|
||||
$(document).on('click', '#btn_submit', function(e) {
|
||||
e.preventDefault(); // Prevent default form submission
|
||||
|
||||
alertLoading("Loading..."); // Show loading alert (your custom function)
|
||||
|
||||
$('#frmAdd').submit();
|
||||
|
||||
/*
|
||||
// Save both editor contents
|
||||
Promise.all([editorDescription.save(), editorDescriptionEn.save()])
|
||||
.then(([descriptionData, descriptionEnData]) => {
|
||||
|
||||
// Store the JSON output in the hidden input fields
|
||||
$('#description_input').val(JSON.stringify(descriptionData));
|
||||
$('#description_input_en').val(JSON.stringify(descriptionEnData));
|
||||
|
||||
// Submit the form after saving the data
|
||||
$('#frmAdd').submit();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error saving editor content:', error);
|
||||
});
|
||||
*/
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,505 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<style>
|
||||
.video-responsive {
|
||||
position: relative;
|
||||
padding-bottom: 56.25%;
|
||||
/* Aspect ratio 16:9 */
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.video-responsive video {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'CHIANG MAI AND NOWHERE ELSE : Edit Sub Category Management',
|
||||
'pageName' => 'Edit',
|
||||
'pageParent' => 'Sub Category Management',
|
||||
'pageParentLink' => url('no-where-else/sub-category'),
|
||||
])
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
|
||||
<form id="frmUpdate" class="form d-flex flex-column flex-lg-row"
|
||||
action="{{ url('no-where-else/update-sub-category') }}" method="post" enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="id" value="{{ $itemView->id }}">
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
{{-- Left --}}
|
||||
<div class="d-flex flex-column gap-7 gap-lg-10 w-100 w-lg-300px mb-7 me-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
<div class="card-body text-center pt-0">
|
||||
|
||||
<style>
|
||||
.image-input-placeholder {
|
||||
background-image: url('{{ url('assets/media/svg/files/blank-image.svg') }}');
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .image-input-placeholder {
|
||||
background-image: url('../media/svg/files/blank-image-dark.svg');
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="image-input image-input-empty image-input-outline image-input-placeholder mb-3"
|
||||
data-kt-image-input="true">
|
||||
|
||||
|
||||
@if ($itemView->image_url && $itemView->image_name)
|
||||
<div class="image-input-wrapper w-150px h-150px"
|
||||
style="background-image: url('{{ $itemView->image_url . '/thumbnail/' . $itemView->image_name }}')">
|
||||
</div>
|
||||
@else
|
||||
<div class="image-input-wrapper w-150px h-150px"></div>
|
||||
@endif
|
||||
|
||||
<label
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="change" data-bs-toggle="tooltip"
|
||||
title="Change avatar">
|
||||
|
||||
<i class="bi bi-pencil-fill fs-7"></i>
|
||||
|
||||
<input type="file" name="avatar" accept=".png, .jpg, .jpeg" />
|
||||
<input type="hidden" name="avatar_remove" />
|
||||
|
||||
</label>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="cancel" data-bs-toggle="tooltip"
|
||||
title="Cancel avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="remove" data-bs-toggle="tooltip"
|
||||
title="Remove avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="text-muted fs-7">Set the profile picture. Only *.png, *.jpg and *.jpeg
|
||||
image
|
||||
files are accepted</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-header" style="border: unset;">
|
||||
<!--begin::Card title-->
|
||||
<div class="required card-title">
|
||||
<h2>Active</h2>
|
||||
</div>
|
||||
<!--end::Card title-->
|
||||
</div>
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<label class="form-check form-switch form-check-custom form-check-solid">
|
||||
<input class="form-check-input" name="active" type="checkbox" value="1"
|
||||
{{ $itemView->active == 1 ? 'checked' : '' }} />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{{-- Right --}}
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
{{-- <div class="mb-10 fv-row">
|
||||
<div class="position-relative d-flex align-items-center">
|
||||
<span class="svg-icon svg-icon-2 position-absolute mx-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21 22H3C2.4 22 2 21.6 2 21V5C2 4.4 2.4 4 3 4H21C21.6 4 22 4.4 22 5V21C22 21.6 21.6 22 21 22Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M6 6C5.4 6 5 5.6 5 5V3C5 2.4 5.4 2 6 2C6.6 2 7 2.4 7 3V5C7 5.6 6.6 6 6 6ZM11 5V3C11 2.4 10.6 2 10 2C9.4 2 9 2.4 9 3V5C9 5.6 9.4 6 10 6C10.6 6 11 5.6 11 5ZM15 5V3C15 2.4 14.6 2 14 2C13.4 2 13 2.4 13 3V5C13 5.6 13.4 6 14 6C14.6 6 15 5.6 15 5ZM19 5V3C19 2.4 18.6 2 18 2C17.4 2 17 2.4 17 3V5C17 5.6 17.4 6 18 6C18.6 6 19 5.6 19 5Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M8.8 13.1C9.2 13.1 9.5 13 9.7 12.8C9.9 12.6 10.1 12.3 10.1 11.9C10.1 11.6 10 11.3 9.8 11.1C9.6 10.9 9.3 10.8 9 10.8C8.8 10.8 8.59999 10.8 8.39999 10.9C8.19999 11 8.1 11.1 8 11.2C7.9 11.3 7.8 11.4 7.7 11.6C7.6 11.8 7.5 11.9 7.5 12.1C7.5 12.2 7.4 12.2 7.3 12.3C7.2 12.4 7.09999 12.4 6.89999 12.4C6.69999 12.4 6.6 12.3 6.5 12.2C6.4 12.1 6.3 11.9 6.3 11.7C6.3 11.5 6.4 11.3 6.5 11.1C6.6 10.9 6.8 10.7 7 10.5C7.2 10.3 7.49999 10.1 7.89999 10C8.29999 9.90003 8.60001 9.80003 9.10001 9.80003C9.50001 9.80003 9.80001 9.90003 10.1 10C10.4 10.1 10.7 10.3 10.9 10.4C11.1 10.5 11.3 10.8 11.4 11.1C11.5 11.4 11.6 11.6 11.6 11.9C11.6 12.3 11.5 12.6 11.3 12.9C11.1 13.2 10.9 13.5 10.6 13.7C10.9 13.9 11.2 14.1 11.4 14.3C11.6 14.5 11.8 14.7 11.9 15C12 15.3 12.1 15.5 12.1 15.8C12.1 16.2 12 16.5 11.9 16.8C11.8 17.1 11.5 17.4 11.3 17.7C11.1 18 10.7 18.2 10.3 18.3C9.9 18.4 9.5 18.5 9 18.5C8.5 18.5 8.1 18.4 7.7 18.2C7.3 18 7 17.8 6.8 17.6C6.6 17.4 6.4 17.1 6.3 16.8C6.2 16.5 6.10001 16.3 6.10001 16.1C6.10001 15.9 6.2 15.7 6.3 15.6C6.4 15.5 6.6 15.4 6.8 15.4C6.9 15.4 7.00001 15.4 7.10001 15.5C7.20001 15.6 7.3 15.6 7.3 15.7C7.5 16.2 7.7 16.6 8 16.9C8.3 17.2 8.6 17.3 9 17.3C9.2 17.3 9.5 17.2 9.7 17.1C9.9 17 10.1 16.8 10.3 16.6C10.5 16.4 10.5 16.1 10.5 15.8C10.5 15.3 10.4 15 10.1 14.7C9.80001 14.4 9.50001 14.3 9.10001 14.3C9.00001 14.3 8.9 14.3 8.7 14.3C8.5 14.3 8.39999 14.3 8.39999 14.3C8.19999 14.3 7.99999 14.2 7.89999 14.1C7.79999 14 7.7 13.8 7.7 13.7C7.7 13.5 7.79999 13.4 7.89999 13.2C7.99999 13 8.2 13 8.5 13H8.8V13.1ZM15.3 17.5V12.2C14.3 13 13.6 13.3 13.3 13.3C13.1 13.3 13 13.2 12.9 13.1C12.8 13 12.7 12.8 12.7 12.6C12.7 12.4 12.8 12.3 12.9 12.2C13 12.1 13.2 12 13.6 11.8C14.1 11.6 14.5 11.3 14.7 11.1C14.9 10.9 15.2 10.6 15.5 10.3C15.8 10 15.9 9.80003 15.9 9.70003C15.9 9.60003 16.1 9.60004 16.3 9.60004C16.5 9.60004 16.7 9.70003 16.8 9.80003C16.9 9.90003 17 10.2 17 10.5V17.2C17 18 16.7 18.4 16.2 18.4C16 18.4 15.8 18.3 15.6 18.2C15.4 18.1 15.3 17.8 15.3 17.5Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
<input class="form-control form-control-solid ps-12" type="text"
|
||||
id="due_date" name="due_date"
|
||||
value="{{ $itemView->due_date ? date('d-m-Y', strtotime($itemView->due_date)) : '' }}">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div> --}}
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Subject</label>
|
||||
<input type="text" name="name" class="form-control mb-2 col-6"
|
||||
value="{{ $itemView->name }}" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Subject (EN)</label>
|
||||
<input type="text" name="name_en" class="form-control mb-2 col-6"
|
||||
value="{{ $itemView->name_en }}" />
|
||||
</div>
|
||||
|
||||
{{-- <div class="mb-10 fv-row">
|
||||
<label class="required form-label">Description</label>
|
||||
<div class="form-control" id="description" name="description"></div>
|
||||
<input type="hidden" id="description_input" name="description" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Description (EN)</label>
|
||||
<div class="form-control" id="description_en" name="description_en"></div>
|
||||
<input type="hidden" id="description_input_en" name="description_en" />
|
||||
|
||||
</div> --}}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('no-where-else/sub-category') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button type="button" id="btn_submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
/*
|
||||
$('#due_date').flatpickr({
|
||||
enableTime: false,
|
||||
dateFormat: 'd-m-Y',
|
||||
defaultDate: null
|
||||
onReady: function(selectedDates, dateStr, instance) {
|
||||
const today = instance.todayDateElem;
|
||||
today.classList.add('flatpickr-today-highlight');
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
/*
|
||||
// file video
|
||||
$('.files-video').fileuploader({
|
||||
extensions: ['MP4', 'mp4', 'MOV', 'mov'],
|
||||
limit: null,
|
||||
fileMaxSize: null,
|
||||
changeInput: '<div class="fileuploader-input">' +
|
||||
'<div class="fileuploader-input-inner">' +
|
||||
'<p><i class="fileuploader-icon-main"></i></p>' +
|
||||
'<h6>Drag and drop files here</h6>' +
|
||||
'<p>or</p>' +
|
||||
'<br>' +
|
||||
'<button type="button" class="fileuploader-input-button"><span>${captions.button}</span></button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
theme: 'dragdrop',
|
||||
});
|
||||
|
||||
// file image
|
||||
$('.files-image').fileuploader({
|
||||
extensions: ['jpg', 'bmp', 'jpeg', 'png'],
|
||||
limit: null,
|
||||
fileMaxSize: null,
|
||||
changeInput: '<div class="fileuploader-input">' +
|
||||
'<div class="fileuploader-input-inner">' +
|
||||
'<p><i class="fileuploader-icon-main"></i></p>' +
|
||||
'<h6>Drag and drop files here</h6>' +
|
||||
'<p>or</p>' +
|
||||
'<br>' +
|
||||
'<button type="button" class="fileuploader-input-button"><span>${captions.button}</span></button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
theme: 'dragdrop',
|
||||
});
|
||||
|
||||
// file sound
|
||||
$('.files-sound').fileuploader({
|
||||
extensions: ['m4a', 'mp4', 'mp3', 'wav'],
|
||||
limit: null,
|
||||
fileMaxSize: null,
|
||||
changeInput: '<div class="fileuploader-input">' +
|
||||
'<div class="fileuploader-input-inner">' +
|
||||
'<p><i class="fileuploader-icon-main"></i></p>' +
|
||||
'<h6>Drag and drop files here</h6>' +
|
||||
'<p>or</p>' +
|
||||
'<br>' +
|
||||
'<button type="button" class="fileuploader-input-button"><span>${captions.button}</span></button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
theme: 'dragdrop',
|
||||
});
|
||||
|
||||
// file document
|
||||
$('.files-document').fileuploader({
|
||||
extensions: ['pdf', 'xls', 'doc', 'docx', 'pptx', 'csv', 'txt'],
|
||||
limit: null,
|
||||
fileMaxSize: null,
|
||||
changeInput: '<div class="fileuploader-input">' +
|
||||
'<div class="fileuploader-input-inner">' +
|
||||
'<p><i class="fileuploader-icon-main"></i></p>' +
|
||||
'<h6>Drag and drop files here</h6>' +
|
||||
'<p>or</p>' +
|
||||
'<br>' +
|
||||
'<button type="button" class="fileuploader-input-button"><span>${captions.button}</span></button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
theme: 'dragdrop',
|
||||
});
|
||||
*/
|
||||
|
||||
$(document).on("click", "#btn_submit", function(e) {
|
||||
e.preventDefault();
|
||||
alertLoading("Loading")
|
||||
const form = $('#frmUpdate');
|
||||
form.submit();
|
||||
})
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<!-- Include Editor.js core -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest"></script>
|
||||
|
||||
<!-- Include the plugins -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/header"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/list"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/paragraph"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/quote"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/image"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/editorjs-inline-image"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/embed"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/code"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/table"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/marker"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/checklist"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/delimiter"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/warning"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/link"></script>
|
||||
|
||||
<script>
|
||||
// Custom video tool for embedding videos
|
||||
/*
|
||||
class VideoTool {
|
||||
constructor({
|
||||
data
|
||||
}) {
|
||||
this.data = data || {};
|
||||
}
|
||||
|
||||
// Render input for video URL
|
||||
render() {
|
||||
const wrapper = document.createElement("div");
|
||||
|
||||
const input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.placeholder = "Enter video URL";
|
||||
input.value = this.data.url || "";
|
||||
input.style.width = "100%";
|
||||
|
||||
const video = document.createElement("video");
|
||||
video.controls = true;
|
||||
video.style.width = "100%";
|
||||
video.style.marginTop = "10px";
|
||||
video.src = this.data.url || "";
|
||||
|
||||
input.addEventListener("input", (event) => {
|
||||
const value = event.target.value;
|
||||
this.data.url = value;
|
||||
video.src = value;
|
||||
});
|
||||
|
||||
wrapper.appendChild(input);
|
||||
wrapper.appendChild(video);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
// Save the video URL
|
||||
save(blockContent) {
|
||||
const input = blockContent.querySelector("input");
|
||||
return {
|
||||
url: input.value,
|
||||
};
|
||||
}
|
||||
|
||||
// Editor.js toolbox definition
|
||||
static get toolbox() {
|
||||
return {
|
||||
title: "Video",
|
||||
icon: '<svg width="20" height="20" viewBox="0 0 24 24"><path d="M10 8.64L15.27 12 10 15.36V8.64M10 3.14L21 12 10 20.86V3.14M3 4h4v16H3V4z"></path></svg>',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const tools = {
|
||||
header: {
|
||||
class: Header,
|
||||
inlineToolbar: ['link', 'bold', 'italic'],
|
||||
config: {
|
||||
placeholder: 'Enter a header',
|
||||
levels: [2, 3, 4], // Set header levels
|
||||
defaultLevel: 3,
|
||||
},
|
||||
},
|
||||
embed: {
|
||||
class: Embed,
|
||||
inlineToolbar: true,
|
||||
config: {
|
||||
services: {
|
||||
youtube: true,
|
||||
vimeo: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
video: {
|
||||
class: VideoTool,
|
||||
inlineToolbar: true,
|
||||
},
|
||||
image: {
|
||||
class: InlineImage,
|
||||
inlineToolbar: true,
|
||||
config: {
|
||||
embed: {
|
||||
display: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
const descriptionData = {!! json_encode($itemView->description) !!};
|
||||
const editorDescription = new EditorJS({
|
||||
holder: 'description',
|
||||
tools: tools,
|
||||
data: descriptionData != "" ? JSON.parse(descriptionData) : {},
|
||||
onChange: () => {
|
||||
saveData(editorDescription, 'description_input')
|
||||
}
|
||||
});
|
||||
|
||||
const descriptionDataEn = {!! json_encode($itemView->description_en) !!};
|
||||
const editorDescriptionEn = new EditorJS({
|
||||
holder: 'description_en',
|
||||
tools: tools,
|
||||
data: descriptionDataEn !== "" ? JSON.parse(descriptionDataEn) : {},
|
||||
onChange: () => {
|
||||
saveData(editorDescriptionEn, 'description_input_en');
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// Function to save data to hidden inputs
|
||||
function saveData(editor, inputId) {
|
||||
editor.save().then((outputData) => {
|
||||
document.getElementById(inputId).value = JSON.stringify(outputData);
|
||||
}).catch((error) => {
|
||||
console.error('Saving failed: ', error);
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '#btn_submit', function(e) {
|
||||
e.preventDefault(); // Prevent default form submission
|
||||
|
||||
alertLoading("Loading..."); // Show loading alert (your custom function)
|
||||
$('#frmUpdate').submit();
|
||||
/*
|
||||
// Save both editor contents
|
||||
Promise.all([editorDescription.save(), editorDescriptionEn.save()])
|
||||
.then(([descriptionData, descriptionEnData]) => {
|
||||
// Store the JSON output in the hidden input fields
|
||||
$('#description_input').val(JSON.stringify(descriptionData));
|
||||
$('#description_input_en').val(JSON.stringify(descriptionEnData));
|
||||
|
||||
// Submit the form after saving the data
|
||||
$('#frmUpdate').submit();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error saving editor content:', error);
|
||||
});
|
||||
*/
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,407 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.breadcrumbList', [
|
||||
'title' => 'CHIANG MAI AND NOWHERE ELSE : Sub Category Management',
|
||||
'pageName' => 'Sub Category Management',
|
||||
])
|
||||
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<!--begin::Content container-->
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
<!--begin::Card-->
|
||||
<div class="card">
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<!--begin::Card header-->
|
||||
<div class="card-header border-0 pt-6">
|
||||
<!--begin::Card title-->
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
</div>
|
||||
|
||||
|
||||
@if (Auth::user()->role != 2)
|
||||
<div class="card-toolbar">
|
||||
<div class="d-flex justify-content-end" data-kt-customer-table-toolbar="base">
|
||||
<a href="{{ url('no-where-else/add-sub-category') }}" class="btn btn-primary">Add
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card-header border-0 pt-5">
|
||||
|
||||
<div class="card-title">
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
<span class="svg-icon svg-icon-1 position-absolute ms-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<rect opacity="0.5" x="17.0365" y="15.1223" width="8.15546" height="2"
|
||||
rx="1" transform="rotate(45 17.0365 15.1223)" fill="currentColor">
|
||||
</rect>
|
||||
<path
|
||||
d="M11 19C6.55556 19 3 15.4444 3 11C3 6.55556 6.55556 3 11 3C15.4444 3 19 6.55556 19 11C19 15.4444 15.4444 19 11 19ZM11 5C7.53333 5 5 7.53333 5 11C5 14.4667 7.53333 17 11 17C14.4667 17 17 14.4667 17 11C17 7.53333 14.4667 5 11 5Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<input type="text" table-filter="search"
|
||||
class="form-control form-control-solid w-250px ps-15" placeholder="Search" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- <div class="card-toolbar flex-row-fluid justify-content-end gap-5">
|
||||
|
||||
<div class="w-100 mw-150px">
|
||||
<div class="position-relative d-flex align-items-center">
|
||||
<span class="svg-icon svg-icon-2 position-absolute mx-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21 22H3C2.4 22 2 21.6 2 21V5C2 4.4 2.4 4 3 4H21C21.6 4 22 4.4 22 5V21C22 21.6 21.6 22 21 22Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M6 6C5.4 6 5 5.6 5 5V3C5 2.4 5.4 2 6 2C6.6 2 7 2.4 7 3V5C7 5.6 6.6 6 6 6ZM11 5V3C11 2.4 10.6 2 10 2C9.4 2 9 2.4 9 3V5C9 5.6 9.4 6 10 6C10.6 6 11 5.6 11 5ZM15 5V3C15 2.4 14.6 2 14 2C13.4 2 13 2.4 13 3V5C13 5.6 13.4 6 14 6C14.6 6 15 5.6 15 5ZM19 5V3C19 2.4 18.6 2 18 2C17.4 2 17 2.4 17 3V5C17 5.6 17.4 6 18 6C18.6 6 19 5.6 19 5Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M8.8 13.1C9.2 13.1 9.5 13 9.7 12.8C9.9 12.6 10.1 12.3 10.1 11.9C10.1 11.6 10 11.3 9.8 11.1C9.6 10.9 9.3 10.8 9 10.8C8.8 10.8 8.59999 10.8 8.39999 10.9C8.19999 11 8.1 11.1 8 11.2C7.9 11.3 7.8 11.4 7.7 11.6C7.6 11.8 7.5 11.9 7.5 12.1C7.5 12.2 7.4 12.2 7.3 12.3C7.2 12.4 7.09999 12.4 6.89999 12.4C6.69999 12.4 6.6 12.3 6.5 12.2C6.4 12.1 6.3 11.9 6.3 11.7C6.3 11.5 6.4 11.3 6.5 11.1C6.6 10.9 6.8 10.7 7 10.5C7.2 10.3 7.49999 10.1 7.89999 10C8.29999 9.90003 8.60001 9.80003 9.10001 9.80003C9.50001 9.80003 9.80001 9.90003 10.1 10C10.4 10.1 10.7 10.3 10.9 10.4C11.1 10.5 11.3 10.8 11.4 11.1C11.5 11.4 11.6 11.6 11.6 11.9C11.6 12.3 11.5 12.6 11.3 12.9C11.1 13.2 10.9 13.5 10.6 13.7C10.9 13.9 11.2 14.1 11.4 14.3C11.6 14.5 11.8 14.7 11.9 15C12 15.3 12.1 15.5 12.1 15.8C12.1 16.2 12 16.5 11.9 16.8C11.8 17.1 11.5 17.4 11.3 17.7C11.1 18 10.7 18.2 10.3 18.3C9.9 18.4 9.5 18.5 9 18.5C8.5 18.5 8.1 18.4 7.7 18.2C7.3 18 7 17.8 6.8 17.6C6.6 17.4 6.4 17.1 6.3 16.8C6.2 16.5 6.10001 16.3 6.10001 16.1C6.10001 15.9 6.2 15.7 6.3 15.6C6.4 15.5 6.6 15.4 6.8 15.4C6.9 15.4 7.00001 15.4 7.10001 15.5C7.20001 15.6 7.3 15.6 7.3 15.7C7.5 16.2 7.7 16.6 8 16.9C8.3 17.2 8.6 17.3 9 17.3C9.2 17.3 9.5 17.2 9.7 17.1C9.9 17 10.1 16.8 10.3 16.6C10.5 16.4 10.5 16.1 10.5 15.8C10.5 15.3 10.4 15 10.1 14.7C9.80001 14.4 9.50001 14.3 9.10001 14.3C9.00001 14.3 8.9 14.3 8.7 14.3C8.5 14.3 8.39999 14.3 8.39999 14.3C8.19999 14.3 7.99999 14.2 7.89999 14.1C7.79999 14 7.7 13.8 7.7 13.7C7.7 13.5 7.79999 13.4 7.89999 13.2C7.99999 13 8.2 13 8.5 13H8.8V13.1ZM15.3 17.5V12.2C14.3 13 13.6 13.3 13.3 13.3C13.1 13.3 13 13.2 12.9 13.1C12.8 13 12.7 12.8 12.7 12.6C12.7 12.4 12.8 12.3 12.9 12.2C13 12.1 13.2 12 13.6 11.8C14.1 11.6 14.5 11.3 14.7 11.1C14.9 10.9 15.2 10.6 15.5 10.3C15.8 10 15.9 9.80003 15.9 9.70003C15.9 9.60003 16.1 9.60004 16.3 9.60004C16.5 9.60004 16.7 9.70003 16.8 9.80003C16.9 9.90003 17 10.2 17 10.5V17.2C17 18 16.7 18.4 16.2 18.4C16 18.4 15.8 18.3 15.6 18.2C15.4 18.1 15.3 17.8 15.3 17.5Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
<input class="form-control form-control-solid ps-12" placeholder="From"
|
||||
id="due_date_from" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="w-100 mw-150px">
|
||||
<div class="position-relative d-flex align-items-center">
|
||||
<span class="svg-icon svg-icon-2 position-absolute mx-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21 22H3C2.4 22 2 21.6 2 21V5C2 4.4 2.4 4 3 4H21C21.6 4 22 4.4 22 5V21C22 21.6 21.6 22 21 22Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M6 6C5.4 6 5 5.6 5 5V3C5 2.4 5.4 2 6 2C6.6 2 7 2.4 7 3V5C7 5.6 6.6 6 6 6ZM11 5V3C11 2.4 10.6 2 10 2C9.4 2 9 2.4 9 3V5C9 5.6 9.4 6 10 6C10.6 6 11 5.6 11 5ZM15 5V3C15 2.4 14.6 2 14 2C13.4 2 13 2.4 13 3V5C13 5.6 13.4 6 14 6C14.6 6 15 5.6 15 5ZM19 5V3C19 2.4 18.6 2 18 2C17.4 2 17 2.4 17 3V5C17 5.6 17.4 6 18 6C18.6 6 19 5.6 19 5Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M8.8 13.1C9.2 13.1 9.5 13 9.7 12.8C9.9 12.6 10.1 12.3 10.1 11.9C10.1 11.6 10 11.3 9.8 11.1C9.6 10.9 9.3 10.8 9 10.8C8.8 10.8 8.59999 10.8 8.39999 10.9C8.19999 11 8.1 11.1 8 11.2C7.9 11.3 7.8 11.4 7.7 11.6C7.6 11.8 7.5 11.9 7.5 12.1C7.5 12.2 7.4 12.2 7.3 12.3C7.2 12.4 7.09999 12.4 6.89999 12.4C6.69999 12.4 6.6 12.3 6.5 12.2C6.4 12.1 6.3 11.9 6.3 11.7C6.3 11.5 6.4 11.3 6.5 11.1C6.6 10.9 6.8 10.7 7 10.5C7.2 10.3 7.49999 10.1 7.89999 10C8.29999 9.90003 8.60001 9.80003 9.10001 9.80003C9.50001 9.80003 9.80001 9.90003 10.1 10C10.4 10.1 10.7 10.3 10.9 10.4C11.1 10.5 11.3 10.8 11.4 11.1C11.5 11.4 11.6 11.6 11.6 11.9C11.6 12.3 11.5 12.6 11.3 12.9C11.1 13.2 10.9 13.5 10.6 13.7C10.9 13.9 11.2 14.1 11.4 14.3C11.6 14.5 11.8 14.7 11.9 15C12 15.3 12.1 15.5 12.1 15.8C12.1 16.2 12 16.5 11.9 16.8C11.8 17.1 11.5 17.4 11.3 17.7C11.1 18 10.7 18.2 10.3 18.3C9.9 18.4 9.5 18.5 9 18.5C8.5 18.5 8.1 18.4 7.7 18.2C7.3 18 7 17.8 6.8 17.6C6.6 17.4 6.4 17.1 6.3 16.8C6.2 16.5 6.10001 16.3 6.10001 16.1C6.10001 15.9 6.2 15.7 6.3 15.6C6.4 15.5 6.6 15.4 6.8 15.4C6.9 15.4 7.00001 15.4 7.10001 15.5C7.20001 15.6 7.3 15.6 7.3 15.7C7.5 16.2 7.7 16.6 8 16.9C8.3 17.2 8.6 17.3 9 17.3C9.2 17.3 9.5 17.2 9.7 17.1C9.9 17 10.1 16.8 10.3 16.6C10.5 16.4 10.5 16.1 10.5 15.8C10.5 15.3 10.4 15 10.1 14.7C9.80001 14.4 9.50001 14.3 9.10001 14.3C9.00001 14.3 8.9 14.3 8.7 14.3C8.5 14.3 8.39999 14.3 8.39999 14.3C8.19999 14.3 7.99999 14.2 7.89999 14.1C7.79999 14 7.7 13.8 7.7 13.7C7.7 13.5 7.79999 13.4 7.89999 13.2C7.99999 13 8.2 13 8.5 13H8.8V13.1ZM15.3 17.5V12.2C14.3 13 13.6 13.3 13.3 13.3C13.1 13.3 13 13.2 12.9 13.1C12.8 13 12.7 12.8 12.7 12.6C12.7 12.4 12.8 12.3 12.9 12.2C13 12.1 13.2 12 13.6 11.8C14.1 11.6 14.5 11.3 14.7 11.1C14.9 10.9 15.2 10.6 15.5 10.3C15.8 10 15.9 9.80003 15.9 9.70003C15.9 9.60003 16.1 9.60004 16.3 9.60004C16.5 9.60004 16.7 9.70003 16.8 9.80003C16.9 9.90003 17 10.2 17 10.5V17.2C17 18 16.7 18.4 16.2 18.4C16 18.4 15.8 18.3 15.6 18.2C15.4 18.1 15.3 17.8 15.3 17.5Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
<input class="form-control form-control-solid ps-12" placeholder="To"
|
||||
id="due_date_to" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="button" id="btn-submit" class="btn btn-primary">
|
||||
Search
|
||||
</button>
|
||||
|
||||
</div> --}}
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-body py-4">
|
||||
<!--begin::Table-->
|
||||
<table class="table align-middle table-row-dashed fs-6 gy-5" id="data-table-category">
|
||||
<!--begin::Table head-->
|
||||
<thead>
|
||||
<!--begin::Table row-->
|
||||
<tr class="text-start text-muted fw-bold fs-7 text-uppercase gs-0">
|
||||
<th class="min-w-125px">Pic</th>
|
||||
<th class="min-w-125px">Subject</th>
|
||||
<th class="min-w-125px">Subject (EN)</th>
|
||||
<th class="min-w-125px">Created</th>
|
||||
<th class="min-w-125px">Active</th>
|
||||
<th class="text-end min-w-100px">Manage</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="text-gray-600 fw-semibold">
|
||||
|
||||
@foreach ($itemView as $obj)
|
||||
<tr>
|
||||
<td class="d-flex align-items-center">
|
||||
<div class="symbol symbol-100px symbol-2by3 me-4">
|
||||
@if ($obj->image_url && $obj->image_name)
|
||||
<a class="show-image-preview d-block overlay"
|
||||
href="{{ url($obj->image_url . '/original/' . $obj->image_name) }}">
|
||||
<div class="symbol-label"
|
||||
style="background-image: url('{{ url($obj->image_url . '/thumbnail/' . $obj->image_name) }}')">
|
||||
</div>
|
||||
</a>
|
||||
@else
|
||||
<div class="symbol-label"
|
||||
style="background-image: url('{{ url('assets/media/avatars/blank.png') }}')">
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" class="text-gray-800 text-hover-primary mb-1">
|
||||
{{ $obj->name }}
|
||||
</a>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<a href="#" class="text-gray-800 text-hover-primary mb-1">
|
||||
{{ $obj->name_en }}
|
||||
</a>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ Carbon\Carbon::parse($obj->created_at)->format('d, M Y') }}
|
||||
</td>
|
||||
|
||||
|
||||
<td>
|
||||
@if ($obj->active == 1)
|
||||
<span class="badge py-3 px-4 fs-7 badge-light-success">Active</span>
|
||||
@else
|
||||
<span class="badge py-3 px-4 fs-7 badge-light-danger">Inactive</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
||||
<td class="min-w-100px text-end">
|
||||
|
||||
{{-- View --}}
|
||||
<a href="{{ url('no-where-else/article/' . $obj->id) }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm me-1">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M17.5 11H6.5C4 11 2 9 2 6.5C2 4 4 2 6.5 2H17.5C20 2 22 4 22 6.5C22 9 20 11 17.5 11ZM15 6.5C15 7.9 16.1 9 17.5 9C18.9 9 20 7.9 20 6.5C20 5.1 18.9 4 17.5 4C16.1 4 15 5.1 15 6.5Z"
|
||||
fill="currentColor"></path>
|
||||
<path opacity="0.3"
|
||||
d="M17.5 22H6.5C4 22 2 20 2 17.5C2 15 4 13 6.5 13H17.5C20 13 22 15 22 17.5C22 20 20 22 17.5 22ZM4 17.5C4 18.9 5.1 20 6.5 20C7.9 20 9 18.9 9 17.5C9 16.1 7.9 15 6.5 15C5.1 15 4 16.1 4 17.5Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{{-- Edit --}}
|
||||
<a href="{{ url('no-where-else/edit-sub-category/' . $obj->id) }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm me-1">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21.4 8.35303L19.241 10.511L13.485 4.755L15.643 2.59595C16.0248 2.21423 16.5426 1.99988 17.0825 1.99988C17.6224 1.99988 18.1402 2.21423 18.522 2.59595L21.4 5.474C21.7817 5.85581 21.9962 6.37355 21.9962 6.91345C21.9962 7.45335 21.7817 7.97122 21.4 8.35303ZM3.68699 21.932L9.88699 19.865L4.13099 14.109L2.06399 20.309C1.98815 20.5354 1.97703 20.7787 2.03189 21.0111C2.08674 21.2436 2.2054 21.4561 2.37449 21.6248C2.54359 21.7934 2.75641 21.9115 2.989 21.9658C3.22158 22.0201 3.4647 22.0084 3.69099 21.932H3.68699Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M5.574 21.3L3.692 21.928C3.46591 22.0032 3.22334 22.0141 2.99144 21.9594C2.75954 21.9046 2.54744 21.7864 2.3789 21.6179C2.21036 21.4495 2.09202 21.2375 2.03711 21.0056C1.9822 20.7737 1.99289 20.5312 2.06799 20.3051L2.696 18.422L5.574 21.3ZM4.13499 14.105L9.891 19.861L19.245 10.507L13.489 4.75098L4.13499 14.105Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{{-- Delete --}}
|
||||
@if ($obj->active == 1 && Auth::user()->role != 2)
|
||||
<a href="#" data-id="{{ $obj->id }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm delete-item">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5 9C5 8.44772 5.44772 8 6 8H18C18.5523 8 19 8.44772 19 9V18C19 19.6569 17.6569 21 16 21H8C6.34315 21 5 19.6569 5 18V9Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M5 5C5 4.44772 5.44772 4 6 4H18C18.5523 4 19 4.44772 19 5V5C19 5.55228 18.5523 6 18 6H6C5.44772 6 5 5.55228 5 5V5Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M9 4C9 3.44772 9.44772 3 10 3H14C14.5523 3 15 3.44772 15 4V4H9V4Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
const baseUrl = "{{ url('no-where-else/sub-category') }}";
|
||||
var datatable;
|
||||
datatable = $("#data-table-category").DataTable({
|
||||
"info": false,
|
||||
"order": [],
|
||||
"pageLength": 25,
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, 500, 1000],
|
||||
[10, 25, 50, 100, 500, 1000]
|
||||
]
|
||||
});
|
||||
|
||||
// Filter by search
|
||||
const filterSearch = document.querySelector('[table-filter="search"]');
|
||||
filterSearch.addEventListener('keyup', function(e) {
|
||||
datatable.search(e.target.value).draw();
|
||||
});
|
||||
|
||||
// filter by status
|
||||
const filterStatus = document.querySelector('[table-filter="status"]');
|
||||
$(filterStatus).on('change', e => {
|
||||
let value = e.target.value;
|
||||
if (value === 'all') {
|
||||
value = '';
|
||||
}
|
||||
datatable.column(4).search(value).draw();
|
||||
});
|
||||
|
||||
|
||||
// Remove
|
||||
$(document).on('click', '.delete-item', function() {
|
||||
swal.fire({
|
||||
allowOutsideClick: false,
|
||||
text: "Are you sure you would like to Delete?",
|
||||
icon: "warning",
|
||||
buttonsStyling: false,
|
||||
showDenyButton: true,
|
||||
confirmButtonText: "Yes",
|
||||
denyButtonText: 'No',
|
||||
customClass: {
|
||||
confirmButton: "btn btn-primary",
|
||||
denyButton: "btn btn-light-danger"
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
// set up ajax
|
||||
initAjaxSetupToken();
|
||||
|
||||
const ajaxProp = {
|
||||
url: "{{ url('no-where-else/delete-sub-category') }}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
item_id: $(this).data('id')
|
||||
},
|
||||
};
|
||||
|
||||
$.ajax(ajaxProp).done(function(res) {
|
||||
if (res.status) {
|
||||
const url = "{{ url('no-where-else/sub-category') }}";
|
||||
alertSuccessWithUrl('Notice', "Delete success", url);
|
||||
hideLoading();
|
||||
} else {
|
||||
alertFail('Notice', res.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
logAjaxError(xhr, status, error);
|
||||
alertFail('Notice', error.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
var today = new Date();
|
||||
var dateFormat = "d-m-Y";
|
||||
|
||||
var dueDateFrom = $("#due_date_from");
|
||||
var dueDateTo = $("#due_date_to");
|
||||
|
||||
const dateFrom = "{{ $fromDateView }}";
|
||||
const dateTo = "{{ $toDateView }}";
|
||||
|
||||
dueDateFrom.flatpickr({
|
||||
showClearButton: true,
|
||||
enableTime: false,
|
||||
dateFormat: dateFormat,
|
||||
maxDate: today,
|
||||
defaultDate: dateFrom,
|
||||
|
||||
});
|
||||
|
||||
dueDateTo.flatpickr({
|
||||
showClearButton: true,
|
||||
enableTime: false,
|
||||
dateFormat: dateFormat,
|
||||
maxDate: today,
|
||||
defaultDate: dateTo,
|
||||
|
||||
});
|
||||
|
||||
const clearDatePicker = () => {
|
||||
dueDateFrom.flatpickr().clear();
|
||||
dueDateTo.flatpickr().clear();
|
||||
|
||||
// Set the date format again after clearing
|
||||
dueDateFrom.flatpickr({
|
||||
dateFormat: dateFormat
|
||||
});
|
||||
dueDateTo.flatpickr({
|
||||
dateFormat: dateFormat
|
||||
});
|
||||
}
|
||||
|
||||
$('#btn-submit').on('click', (e) => {
|
||||
e.preventDefault(); // Prevent the default behavior of the anchor element
|
||||
|
||||
// from
|
||||
const fromDateSelected = $("#due_date_from").val();
|
||||
|
||||
// to
|
||||
const toDateSelected = $("#due_date_to").val();
|
||||
|
||||
if (fromDateSelected && toDateSelected) {
|
||||
var newUrl =
|
||||
`${baseUrl}/${fromDateSelected}/${toDateSelected}`;
|
||||
window.location.href = newUrl;
|
||||
} else {
|
||||
var newUrl = `${baseUrl}/all/all/`;
|
||||
window.location.href = newUrl;
|
||||
}
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,212 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'User Add',
|
||||
'pageName' => 'Add',
|
||||
'pageParent' => 'Users Management',
|
||||
'pageParentLink' => url('user'),
|
||||
])
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
|
||||
<form class="form d-flex flex-column flex-lg-row" action="{{ url('user/insert') }}" method="post"
|
||||
enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
<div class="d-flex flex-column gap-7 gap-lg-10 w-100 w-lg-300px mb-7 me-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
|
||||
<div class="card-header">
|
||||
|
||||
<div class="required card-title">
|
||||
<h2>Profile Picture</h2>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-body text-center pt-0">
|
||||
|
||||
<style>
|
||||
.image-input-placeholder {
|
||||
background-image: url('{{ url('assets/media/svg/files/blank-image.svg') }}');
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .image-input-placeholder {
|
||||
background-image: url('{{ url('assets/media/svg/files/blank-image-dark.svg') }}');
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="image-input image-input-empty image-input-outline image-input-placeholder mb-3"
|
||||
data-kt-image-input="true">
|
||||
|
||||
<div class="image-input-wrapper w-150px h-150px"></div>
|
||||
|
||||
<label
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="change" data-bs-toggle="tooltip"
|
||||
title="Change avatar">
|
||||
|
||||
<i class="bi bi-pencil-fill fs-7"></i>
|
||||
|
||||
<input type="file" name="avatar" accept=".png, .jpg, .jpeg" />
|
||||
<input type="hidden" name="avatar_remove" />
|
||||
|
||||
</label>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="cancel" data-bs-toggle="tooltip"
|
||||
title="Cancel avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="remove" data-bs-toggle="tooltip"
|
||||
title="Remove avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="text-muted fs-7">Set the profile picture. Only *.png, *.jpg and *.jpeg image
|
||||
files are accepted</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Role</label>
|
||||
<div class="d-flex fv-row me-1 mb-5">
|
||||
<div class="form-check form-check-custom form-check-solid">
|
||||
<input class="form-check-input me-3" name="role" type="radio"
|
||||
value="0" checked="checked" data-gtm-form-interact-field-id="1">
|
||||
<label class="form-check-label" for="kt_modal_update_role_option_0">
|
||||
<div class="fw-bold text-gray-800">Administrator</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex fv-row me-1 mb-5">
|
||||
<div class="form-check form-check-custom form-check-solid">
|
||||
<input class="form-check-input me-3" name="role" type="radio"
|
||||
value="1" data-gtm-form-interact-field-id="1">
|
||||
<label class="form-check-label" for="kt_modal_update_role_option_0">
|
||||
<div class="fw-bold text-gray-800">Editor</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex fv-row me-1 mb-5">
|
||||
<div class="form-check form-check-custom form-check-solid">
|
||||
<input class="form-check-input me-3" name="role" type="radio"
|
||||
value="2" data-gtm-form-interact-field-id="1">
|
||||
<label class="form-check-label" for="kt_modal_update_role_option_0">
|
||||
<div class="fw-bold text-gray-800">Contributor</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Firstname</label>
|
||||
<input type="text" name="first_name" class="form-control mb-2 col-6"
|
||||
value="{{ old('first_name') }}" />
|
||||
</div>
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Lastname</label>
|
||||
<input type="text" name="last_name" class="form-control mb-2 col-6"
|
||||
value="{{ old('last_name') }}" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">E-mail</label>
|
||||
<input type="email" name="email" class="form-control mb-2"
|
||||
value="{{ old('email') }}" />
|
||||
</div>
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Password</label>
|
||||
<input type="password" name="password" class="form-control mb-2" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('user') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {});
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,244 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'User Edit',
|
||||
'pageName' => 'Edit',
|
||||
'pageParent' => 'Users Management',
|
||||
'pageParentLink' => url('user'),
|
||||
])
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
|
||||
<form class="form d-flex flex-column flex-lg-row" action="{{ url('user/update') }}" method="post"
|
||||
enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="userId" value="{{ $userView->id }}">
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
<div class="d-flex flex-column gap-7 gap-lg-10 w-100 w-lg-300px mb-7 me-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
<div class="card-header">
|
||||
|
||||
<div class="required card-title">
|
||||
<h2>Profile Picture</h2>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-body text-center pt-0">
|
||||
|
||||
<style>
|
||||
.image-input-placeholder {
|
||||
background-image: url('{{ url('assets/media/svg/files/blank-image.svg') }}');
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .image-input-placeholder {
|
||||
background-image: url('{{ url('assets/media/svg/files/blank-image-dark.svg') }}');
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="image-input image-input-empty image-input-outline image-input-placeholder mb-3"
|
||||
data-kt-image-input="true">
|
||||
|
||||
@if ($userView->image_url && $userView->image_name)
|
||||
<div class="image-input-wrapper w-150px h-150px"
|
||||
style="background-image: url('{{ $userView->image_url . '/thumbnail/' . $userView->image_name }}')">
|
||||
</div>
|
||||
@else
|
||||
<div class="image-input-wrapper w-150px h-150px"></div>
|
||||
@endif
|
||||
|
||||
<label
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="change" data-bs-toggle="tooltip"
|
||||
title="Change avatar">
|
||||
|
||||
<i class="bi bi-pencil-fill fs-7"></i>
|
||||
|
||||
<input type="file" name="avatar" accept=".png, .jpg, .jpeg" />
|
||||
<input type="hidden" name="avatar_remove" />
|
||||
|
||||
</label>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="cancel" data-bs-toggle="tooltip"
|
||||
title="Cancel avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow"
|
||||
data-kt-image-input-action="remove" data-bs-toggle="tooltip"
|
||||
title="Remove avatar">
|
||||
<i class="bi bi-x fs-2"></i>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="text-muted fs-7">Set the profile picture. Only *.png, *.jpg and *.jpeg image
|
||||
files are accepted</div>
|
||||
|
||||
|
||||
{{-- Active --}}
|
||||
<div class="card-header" style="border: unset;">
|
||||
<!--begin::Card title-->
|
||||
<div class="required card-title">
|
||||
<h2>Active</h2>
|
||||
</div>
|
||||
<!--end::Card title-->
|
||||
</div>
|
||||
<div class="card-body pt-0">
|
||||
<label class="form-check form-switch form-check-custom form-check-solid">
|
||||
<input class="form-check-input" name="active" type="checkbox" value="1"
|
||||
{{ $userView->active == 1 ? 'checked' : '' }} />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Role</label>
|
||||
<div class="d-flex fv-row me-1 mb-5">
|
||||
<div class="form-check form-check-custom form-check-solid">
|
||||
<input class="form-check-input me-3" name="role" type="radio"
|
||||
value="0" @if ($userView->role == 0) checked @endif
|
||||
data-gtm-form-interact-field-id="1">
|
||||
<label class="form-check-label" for="kt_modal_update_role_option_0">
|
||||
<div class="fw-bold text-gray-800">Administrator</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex fv-row me-1 mb-5">
|
||||
<div class="form-check form-check-custom form-check-solid">
|
||||
<input class="form-check-input me-3" name="role" type="radio"
|
||||
value="1" @if ($userView->role == 1) checked @endif
|
||||
data-gtm-form-interact-field-id="1">
|
||||
<label class="form-check-label" for="kt_modal_update_role_option_0">
|
||||
<div class="fw-bold text-gray-800">Editor</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex fv-row me-1 mb-5">
|
||||
<div class="form-check form-check-custom form-check-solid">
|
||||
<input class="form-check-input me-3" name="role" type="radio"
|
||||
value="2" @if ($userView->role == 2) checked @endif
|
||||
data-gtm-form-interact-field-id="1">
|
||||
<label class="form-check-label" for="kt_modal_update_role_option_0">
|
||||
<div class="fw-bold text-gray-800">Contributor</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Firstname</label>
|
||||
<input type="text" name="first_name" class="form-control mb-2 col-6"
|
||||
value="{{ $userView->first_name }}" />
|
||||
</div>
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Lastname</label>
|
||||
<input type="text" name="last_name" class="form-control mb-2 col-6"
|
||||
value="{{ $userView->last_name }}" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
|
||||
<label class="required form-label">E-mail</label>
|
||||
|
||||
|
||||
<input type="email" name="email" class="form-control mb-2"
|
||||
value="{{ $userView->email }}" />
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="form-label">Password</label>
|
||||
<input type="password" name="password" class="form-control mb-2" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('user') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {});
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,357 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumbList', [
|
||||
'title' => 'Users Management',
|
||||
'pageName' => 'User Management',
|
||||
])
|
||||
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<!--begin::Content container-->
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
<!--begin::Card-->
|
||||
<div class="card">
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<!--begin::Card header-->
|
||||
<div class="card-header border-0 pt-6">
|
||||
<!--begin::Card title-->
|
||||
<div class="card-title">
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
<span class="svg-icon svg-icon-1 position-absolute ms-6">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<rect opacity="0.5" x="17.0365" y="15.1223" width="8.15546" height="2"
|
||||
rx="1" transform="rotate(45 17.0365 15.1223)" fill="currentColor" />
|
||||
<path
|
||||
d="M11 19C6.55556 19 3 15.4444 3 11C3 6.55556 6.55556 3 11 3C15.4444 3 19 6.55556 19 11C19 15.4444 15.4444 19 11 19ZM11 5C7.53333 5 5 7.53333 5 11C5 14.4667 7.53333 17 11 17C14.4667 17 17 14.4667 17 11C17 7.53333 14.4667 5 11 5Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
<input type="text" table-filter="search"
|
||||
class="form-control form-control-solid w-250px ps-15" placeholder="Search" />
|
||||
</div>
|
||||
</div>
|
||||
<!--begin::Card title-->
|
||||
<!--begin::Card toolbar-->
|
||||
<div class="card-toolbar">
|
||||
|
||||
<div class="w-150px me-3">
|
||||
<select class="form-select form-select-solid" data-control="select2"
|
||||
data-hide-search="true" data-placeholder="Status" table-filter="status">
|
||||
<option></option>
|
||||
<option value="all">All</option>
|
||||
<option value="active">Active</option>
|
||||
<option value="inactive">Inactive</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!--begin::Toolbar-->
|
||||
<div class="d-flex justify-content-end" data-kt-customer-table-toolbar="base">
|
||||
<a href="{{ url('user/add') }}" class="btn btn-primary">Add </a>
|
||||
</div>
|
||||
<!--end::Toolbar-->
|
||||
</div>
|
||||
<!--end::Card toolbar-->
|
||||
</div>
|
||||
<!--end::Card header-->
|
||||
|
||||
|
||||
<div class="card-body py-4">
|
||||
<!--begin::Table-->
|
||||
<table class="table align-middle table-row-dashed fs-6 gy-5" id="data-table-user">
|
||||
<!--begin::Table head-->
|
||||
<thead>
|
||||
<!--begin::Table row-->
|
||||
<tr class="text-start text-muted fw-bold fs-7 text-uppercase gs-0">
|
||||
<th class="min-w-150px">Pic</th>
|
||||
<th class="min-w-150px">Role</th>
|
||||
<th class="min-w-150px">First Name</th>
|
||||
<th class="min-w-150px">Last Name</th>
|
||||
<th class="min-w-150px">Email</th>
|
||||
<th class="min-w-150px">Status</th>
|
||||
<th class="min-w-150px">Created At</th>
|
||||
<th class="min-w-100px text-end">Actions</th>
|
||||
</tr>
|
||||
<!--end::Table row-->
|
||||
</thead>
|
||||
|
||||
<tbody class="fw-bold text-gray-600">
|
||||
@foreach ($userView as $key => $obj)
|
||||
<tr>
|
||||
|
||||
|
||||
<td class="d-flex align-items-center">
|
||||
<div class="symbol symbol-100px symbol-2by3 me-4">
|
||||
@if ($obj->image_url && $obj->image_name)
|
||||
<a class="show-image-preview d-block overlay"
|
||||
href="{{ url($obj->image_url . '/original/' . $obj->image_name) }}">
|
||||
<div class="symbol-label"
|
||||
style="background-image: url('{{ url($obj->image_url . '/thumbnail/' . $obj->image_name) }}')">
|
||||
</div>
|
||||
</a>
|
||||
@else
|
||||
<div class="symbol-label"
|
||||
style="background-image: url('{{ url('assets/media/avatars/blank.png') }}')">
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
@if ($obj->role == 1)
|
||||
<span class="badge py-3 px-4 fs-7 badge-light-warning"> EDITOR </span>
|
||||
@elseif($obj->role == 2)
|
||||
<span class="badge py-3 px-4 fs-7 badge-light-info"> CONTRIBUTOR </span>
|
||||
@else
|
||||
<span class="badge py-3 px-4 fs-7 badge-light-success"> ADMIN </span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td class="">{{ $obj->first_name }}</td>
|
||||
<td class="">{{ $obj->last_name }}</td>
|
||||
<td class="">{{ $obj->email }}</td>
|
||||
<td class="">
|
||||
@if ($obj->active == 1)
|
||||
<span class="badge py-3 px-4 fs-7 badge-light-success">Active</span>
|
||||
@else
|
||||
<span class="badge py-3 px-4 fs-7 badge-light-danger">Locked</span>
|
||||
@endif
|
||||
</td>
|
||||
<td class="">{{ date('d M, Y', strtotime($obj->created_at)) }}</td>
|
||||
<td class="min-w-100px text-end">
|
||||
|
||||
{{-- Edit --}}
|
||||
<a href="{{ url('user/edit/' . $obj->id) }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm me-1">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21.4 8.35303L19.241 10.511L13.485 4.755L15.643 2.59595C16.0248 2.21423 16.5426 1.99988 17.0825 1.99988C17.6224 1.99988 18.1402 2.21423 18.522 2.59595L21.4 5.474C21.7817 5.85581 21.9962 6.37355 21.9962 6.91345C21.9962 7.45335 21.7817 7.97122 21.4 8.35303ZM3.68699 21.932L9.88699 19.865L4.13099 14.109L2.06399 20.309C1.98815 20.5354 1.97703 20.7787 2.03189 21.0111C2.08674 21.2436 2.2054 21.4561 2.37449 21.6248C2.54359 21.7934 2.75641 21.9115 2.989 21.9658C3.22158 22.0201 3.4647 22.0084 3.69099 21.932H3.68699Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M5.574 21.3L3.692 21.928C3.46591 22.0032 3.22334 22.0141 2.99144 21.9594C2.75954 21.9046 2.54744 21.7864 2.3789 21.6179C2.21036 21.4495 2.09202 21.2375 2.03711 21.0056C1.9822 20.7737 1.99289 20.5312 2.06799 20.3051L2.696 18.422L5.574 21.3ZM4.13499 14.105L9.891 19.861L19.245 10.507L13.489 4.75098L4.13499 14.105Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{{-- Delete --}}
|
||||
@if ($obj->active == 1)
|
||||
<a href="#" data-id="{{ $obj->id }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm delete-item">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5 9C5 8.44772 5.44772 8 6 8H18C18.5523 8 19 8.44772 19 9V18C19 19.6569 17.6569 21 16 21H8C6.34315 21 5 19.6569 5 18V9Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M5 5C5 4.44772 5.44772 4 6 4H18C18.5523 4 19 4.44772 19 5V5C19 5.55228 18.5523 6 18 6H6C5.44772 6 5 5.55228 5 5V5Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M9 4C9 3.44772 9.44772 3 10 3H14C14.5523 3 15 3.44772 15 4V4H9V4Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
@endif
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{{-- <div class="modal fade" id="deleteModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered mw-650px">
|
||||
|
||||
<form class="form-horizontal" action="{{ url('user/delete') }}" method="POST">
|
||||
|
||||
<input type="hidden" id="item_id" name="item_id" value="">
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
<div class="modal-content">
|
||||
|
||||
<!--begin::Modal body-->
|
||||
<div class="modal-body scroll-y mx-5 mx-xl-15 my-7">
|
||||
<!--begin::Notice-->
|
||||
<!--begin::Notice-->
|
||||
<div class="notice d-flex bg-light-warning rounded border-warning border border-dashed mb-9 p-6">
|
||||
<!--begin::Icon-->
|
||||
<!--begin::Svg Icon | path: icons/duotune/general/gen044.svg-->
|
||||
<span class="svg-icon svg-icon-2tx svg-icon-warning me-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<rect opacity="0.3" x="2" y="2" width="20" height="20"
|
||||
rx="10" fill="currentColor" />
|
||||
<rect x="11" y="14" width="7" height="2" rx="1"
|
||||
transform="rotate(-90 11 14)" fill="currentColor" />
|
||||
<rect x="11" y="17" width="2" height="2" rx="1"
|
||||
transform="rotate(-90 11 17)" fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<div class="d-flex flex-stack flex-grow-1">
|
||||
<!--begin::Content-->
|
||||
<div class="fw-semibold">
|
||||
<div class="fs-6 text-gray-700">
|
||||
<strong class="me-1">Confirm Delete</strong>
|
||||
Please ensure you're absolutely certain
|
||||
before proceeding.
|
||||
</div>
|
||||
</div>
|
||||
<!--end::Content-->
|
||||
</div>
|
||||
<!--end::Wrapper-->
|
||||
</div>
|
||||
<!--end::Notice-->
|
||||
|
||||
|
||||
|
||||
<!--begin::Actions-->
|
||||
<div class="text-center pt-15">
|
||||
|
||||
<div class="swal2-actions" style="display: flex;">
|
||||
<div class="swal2-loader"></div>
|
||||
<button type="submit" class="btn fw-bold btn-danger" aria-label=""
|
||||
style="display: inline-block;">Yes
|
||||
</button>
|
||||
<button type="reset" class="btn btn-light fw-bold btn-active-light-primary hide-item"
|
||||
aria-label="" style="display: inline-block; margin-left:10px;">No
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!--end::Actions-->
|
||||
|
||||
</div>
|
||||
<!--end::Modal body-->
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div> --}}
|
||||
|
||||
@stop
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
var datatable;
|
||||
datatable = $("#data-table-user").DataTable({
|
||||
"info": false,
|
||||
"order": [],
|
||||
"pageLength": 25,
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, 500, 1000],
|
||||
[10, 25, 50, 100, 500, 1000]
|
||||
]
|
||||
});
|
||||
|
||||
// Filter by search
|
||||
const filterSearch = document.querySelector('[table-filter="search"]');
|
||||
filterSearch.addEventListener('keyup', function(e) {
|
||||
datatable.search(e.target.value).draw();
|
||||
});
|
||||
|
||||
// filter by status
|
||||
const filterStatus = document.querySelector('[table-filter="status"]');
|
||||
$(filterStatus).on('change', e => {
|
||||
let value = e.target.value;
|
||||
if (value === 'all') {
|
||||
value = '';
|
||||
}
|
||||
datatable.column(5).search(value).draw();
|
||||
});
|
||||
|
||||
// Remove
|
||||
$(document).on('click', '.delete-item', function() {
|
||||
// $('#deleteModal #item_id').val($(this).data('id'));
|
||||
// showModal('#deleteModal');
|
||||
|
||||
swal.fire({
|
||||
allowOutsideClick: false,
|
||||
text: "Are you sure you would like to Delete?",
|
||||
icon: "warning",
|
||||
buttonsStyling: false,
|
||||
showDenyButton: true,
|
||||
confirmButtonText: "Yes",
|
||||
denyButtonText: 'No',
|
||||
customClass: {
|
||||
confirmButton: "btn btn-primary",
|
||||
denyButton: "btn btn-light-danger"
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
// set up ajax
|
||||
initAjaxSetupToken();
|
||||
|
||||
const ajaxProp = {
|
||||
url: "{{ url('user/delete') }}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
item_id: $(this).data('id')
|
||||
},
|
||||
};
|
||||
|
||||
$.ajax(ajaxProp).done(function(res) {
|
||||
if (isAjaxStatusSuccess(res.status)) {
|
||||
const url = "{{ url('user') }}";
|
||||
alertSuccessWithUrl('Notice', "Delete success", url);
|
||||
hideLoading();
|
||||
} else {
|
||||
alertFail('Notice', res.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
logAjaxError(xhr, status, error);
|
||||
alertFail('Notice', error.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// $(document).on('click', '.hide-item', function() {
|
||||
// hideModal('#deleteModal');
|
||||
// });
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,367 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<style>
|
||||
#progressBar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
border-radius: 5px;
|
||||
margin-top: 10px;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.progress-bar::-webkit-progress-value {
|
||||
background-color: #4CAF50;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
margin-top: 10px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'Video Add',
|
||||
'pageName' => 'Add',
|
||||
'pageParent' => 'Video Management',
|
||||
'pageParentLink' => url('video'),
|
||||
])
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
|
||||
|
||||
<form id="frmAdd" class="form d-flex flex-column flex-lg-row" method="post"
|
||||
enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<div class="mb-10">
|
||||
<label class="form-label required">File Video</label>
|
||||
|
||||
<input class="fileInput file-input" type="file" id="fileInput" name="fileInput"
|
||||
multiple accept=".MP4, .MOV">
|
||||
|
||||
<progress id="progressBar" class="progress-bar" value="0"
|
||||
max="100"></progress>
|
||||
<div id="progressText" class="progress-text">0%</div>
|
||||
|
||||
<div class="text-muted fs-7">Allowed Types .MP4, .MOV</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('video') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button type="button" id="btn_submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script>
|
||||
const baseApiUrl = "{{ env('API_URL') }}";
|
||||
|
||||
|
||||
$(document).on("click", "#btn_submit", async function(e) {
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
await uploadFile();
|
||||
|
||||
});
|
||||
|
||||
|
||||
// Step 1
|
||||
async function uploadFile() {
|
||||
const fileInput = document.getElementById("fileInput");
|
||||
const progressBar = document.getElementById("progressBar");
|
||||
const progressText = document.getElementById("progressText");
|
||||
|
||||
if (!fileInput || fileInput.files.length === 0) {
|
||||
alertFail("Notice", "Please select one or more files.");
|
||||
hideLoading();
|
||||
return;
|
||||
}
|
||||
|
||||
const files = Array.from(fileInput.files); // Get all selected files
|
||||
$("#progressBar").show();
|
||||
|
||||
let totalSize = files.reduce((sum, file) => sum + file.size, 0);
|
||||
let totalUploadedSize = 0;
|
||||
|
||||
// Upload all files sequentially
|
||||
for (const file of files) {
|
||||
await uploadSingleFile(file, progressBar, progressText, totalSize, (fileUploadedSize) => {
|
||||
totalUploadedSize += fileUploadedSize;
|
||||
const overallPercent = Math.floor((totalUploadedSize / totalSize) * 100);
|
||||
animateProgress(progressBar, progressText, overallPercent);
|
||||
});
|
||||
}
|
||||
|
||||
const folderId = "{{ $folderIdView }}";
|
||||
let redirectUrl = "{{ url('video') }}"
|
||||
if (folderId) {
|
||||
redirectUrl = `${redirectUrl}/folder/${folderId}`;
|
||||
}
|
||||
|
||||
alertSuccessWithUrl("Notice", "All files uploaded successfully", redirectUrl);
|
||||
}
|
||||
|
||||
async function uploadSingleFile(file, progressBar, progressText, totalSize, updateOverallProgress) {
|
||||
const uploadId = await initiateMultipartUpload(file.name);
|
||||
const partSize = 500 * 1024 * 1024; // 500 MB per part
|
||||
const parts = [];
|
||||
let uploadedSize = 0;
|
||||
|
||||
const uploadPromises = Array.from({
|
||||
length: Math.ceil(file.size / partSize)
|
||||
},
|
||||
(_, index) => {
|
||||
const partNumber = index + 1;
|
||||
const chunk = file.slice(index * partSize, (index + 1) * partSize);
|
||||
|
||||
return (async () => {
|
||||
const presignedUrl = await getPresignedUrl(uploadId, partNumber, file.name);
|
||||
const etag = await uploadPartToS3(presignedUrl, chunk);
|
||||
|
||||
parts.push({
|
||||
PartNumber: partNumber,
|
||||
ETag: etag
|
||||
});
|
||||
|
||||
uploadedSize += chunk.size;
|
||||
updateOverallProgress(chunk.size); // Update the overall progress
|
||||
})();
|
||||
}
|
||||
);
|
||||
|
||||
await Promise.all(uploadPromises);
|
||||
await completeMultipartUpload(uploadId, parts, file.name);
|
||||
await saveFileNameToDB(file.name);
|
||||
}
|
||||
|
||||
// Step 2
|
||||
async function initiateMultipartUpload(fileName) {
|
||||
const urlUploadImage = `${baseApiUrl}/initiate-multipart-upload`;
|
||||
const response = await fetch(
|
||||
urlUploadImage, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
fileName
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
const {
|
||||
uploadId
|
||||
} = await response.json();
|
||||
|
||||
return uploadId;
|
||||
}
|
||||
|
||||
// Step 3
|
||||
async function getPresignedUrl(uploadId, partNumber, fileName) {
|
||||
|
||||
const urlPresigned = `${baseApiUrl}/get-presigned-url`
|
||||
const response = await fetch(
|
||||
urlPresigned, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
uploadId,
|
||||
partNumber,
|
||||
fileName
|
||||
}),
|
||||
}
|
||||
);
|
||||
const {
|
||||
url
|
||||
} = await response.json();
|
||||
return url;
|
||||
}
|
||||
|
||||
// Step 4
|
||||
async function uploadPartToS3(url, chunk) {
|
||||
const response = await fetch(url, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/octet-stream",
|
||||
},
|
||||
body: chunk,
|
||||
});
|
||||
if (!response.ok) {
|
||||
alertFail("Notice", "Failed to upload part")
|
||||
hideLoading();
|
||||
//throw new Error("Failed to upload part");
|
||||
}
|
||||
|
||||
const etag = `${response.headers.get("ETag")}`.replace(/"/g, "");
|
||||
|
||||
if (!etag) {
|
||||
throw new Error("Failed to retrieve ETag from the response.");
|
||||
}
|
||||
|
||||
return etag;
|
||||
}
|
||||
|
||||
// Step 5
|
||||
async function completeMultipartUpload(uploadId, parts, fileName) {
|
||||
const urlUploadComplete = `${baseApiUrl}/complete-multipart-upload`;
|
||||
const response = await fetch(urlUploadComplete, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
uploadId,
|
||||
parts,
|
||||
fileName
|
||||
}),
|
||||
});
|
||||
if (response.ok) {
|
||||
//window.location.href = "{{ url('image') }}";
|
||||
} else {
|
||||
alertFail("Notice", "Failed to upload part");
|
||||
hideLoading();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Smoothly animates the progress bar and percentage text.
|
||||
*/
|
||||
async function animateProgress(progressBar, progressText, targetPercent) {
|
||||
const currentPercent = parseInt(progressBar.value) || 0;
|
||||
// Increment the percentage smoothly
|
||||
for (let percent = currentPercent + 1; percent <= targetPercent; percent++) {
|
||||
progressBar.value = percent;
|
||||
progressText.textContent = `${percent}%`;
|
||||
|
||||
// Add a small delay to make the increment visible (10ms delay)
|
||||
await new Promise((resolve) => setTimeout(resolve, 10));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the uploaded file name to the server using AJAX.
|
||||
*/
|
||||
function saveFileNameToDB(fileName) {
|
||||
initAjaxSetupToken();
|
||||
|
||||
const folderId = "{{ $folderIdView }}";
|
||||
const url = "{{ url('') }}";
|
||||
|
||||
return $.ajax({
|
||||
url: `${url}/video/insert`,
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({
|
||||
fileName,
|
||||
folderId
|
||||
}),
|
||||
success: (response) => {
|
||||
console.log('File name saved:', response);
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Error saving file name:', err);
|
||||
alertFail("Notice", "There was an error saving the file name.");
|
||||
hideLoading();
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
$('.file-input').fileuploader({
|
||||
extensions: ['MP4', 'mp4', 'MOV', 'mov'],
|
||||
limit: null,
|
||||
fileMaxSize: null,
|
||||
changeInput: '<div class="fileuploader-input">' +
|
||||
'<div class="fileuploader-input-inner">' +
|
||||
'<p><i class="fileuploader-icon-main"></i></p>' +
|
||||
'<h6>Drag and drop files here</h6>' +
|
||||
'<p>or</p>' +
|
||||
'<br>' +
|
||||
'<button type="button" class="fileuploader-input-button"><span>${captions.button}</span></button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
theme: 'dragdrop',
|
||||
});
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,95 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'Video Create Folder',
|
||||
'pageName' => 'Create folder',
|
||||
'pageParent' => 'Video Management',
|
||||
'pageParentLink' => url('video'),
|
||||
])
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
<form id="frmAdd" action="{{ url('video/insert-folder') }}" class="form d-flex flex-column flex-lg-row"
|
||||
method="post" enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Name</label>
|
||||
<input type="text" name="name" class="form-control mb-2 col-6"
|
||||
value="{{ old('name') }}" />
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('video') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script></script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,96 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.admin.breadcrumb', [
|
||||
'title' => 'Video Edit Folder',
|
||||
'pageName' => 'Edit folder',
|
||||
'pageParent' => 'Video Management',
|
||||
'pageParentLink' => url('Video'),
|
||||
])
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
<form id="frmAdd" action="{{ url('video/update-folder') }}" class="form d-flex flex-column flex-lg-row"
|
||||
method="post" enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="id" value="{{ $idView }}">
|
||||
<input type="hidden" name="_method" value="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
<div class="d-flex flex-column flex-row-fluid gap-7 gap-lg-10">
|
||||
|
||||
<div class="card card-flush py-4">
|
||||
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h2>Overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-0">
|
||||
|
||||
<div class="mb-10 fv-row">
|
||||
<label class="required form-label">Name</label>
|
||||
<input type="text" name="name" class="form-control mb-2 col-6"
|
||||
value="{{ $itemView->name }}" />
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
|
||||
<a href="{{ url('video') }}" id="kt_ecommerce_add_product_cancel"
|
||||
class="btn btn-light me-5">Cancel</a>
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<span class="indicator-label">Save</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script></script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,310 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<style>
|
||||
.link-container {
|
||||
display: flex;
|
||||
/* Use flexbox for alignment */
|
||||
align-items: center;
|
||||
/* Center items vertically */
|
||||
justify-content: space-between;
|
||||
/* Space between the URL and button */
|
||||
}
|
||||
|
||||
.file-url {
|
||||
flex: 1;
|
||||
/* Allow the URL to take up available space */
|
||||
color: #007bff;
|
||||
/* Link color */
|
||||
text-decoration: none;
|
||||
/* Remove underline */
|
||||
overflow: hidden;
|
||||
/* Hide overflow */
|
||||
white-space: nowrap;
|
||||
/* Prevent text wrapping */
|
||||
text-overflow: ellipsis;
|
||||
/* Add ellipsis for overflow */
|
||||
margin-right: 10px;
|
||||
/* Space between text and button */
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.breadcrumbList', [
|
||||
'title' => 'Video Management Folder ' . $folderView->name,
|
||||
'pageName' => 'Video Management',
|
||||
])
|
||||
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
<div class="card">
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<div class="card-header border-0 pt-6">
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
</div>
|
||||
|
||||
@if (Auth::user()->role != 2)
|
||||
<div class="card-toolbar">
|
||||
<div class="d-flex justify-content-end" data-kt-customer-table-toolbar="base">
|
||||
<a href="{{ url('video/add/' . $folderView->id) }}" class="btn btn-primary">Add
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card-header border-0 pt-5">
|
||||
|
||||
<div class="card-title">
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
<span class="svg-icon svg-icon-1 position-absolute ms-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<rect opacity="0.5" x="17.0365" y="15.1223" width="8.15546" height="2"
|
||||
rx="1" transform="rotate(45 17.0365 15.1223)" fill="currentColor">
|
||||
</rect>
|
||||
<path
|
||||
d="M11 19C6.55556 19 3 15.4444 3 11C3 6.55556 6.55556 3 11 3C15.4444 3 19 6.55556 19 11C19 15.4444 15.4444 19 11 19ZM11 5C7.53333 5 5 7.53333 5 11C5 14.4667 7.53333 17 11 17C14.4667 17 17 14.4667 17 11C17 7.53333 14.4667 5 11 5Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<input type="text" table-filter="search"
|
||||
class="form-control form-control-solid w-250px ps-15" placeholder="Search" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-body py-4">
|
||||
<!--begin::Table-->
|
||||
<table class="table align-middle table-row-dashed fs-6 gy-5" id="data-table">
|
||||
<!--begin::Table head-->
|
||||
<thead>
|
||||
<!--begin::Table row-->
|
||||
<tr class="text-start text-muted fw-bold fs-7 text-uppercase gs-0">
|
||||
<th class="min-w-125px">Name</th>
|
||||
<th class="min-w-125px">Created</th>
|
||||
<th class="text-end min-w-100px">Manage</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="text-gray-600 fw-semibold">
|
||||
|
||||
@foreach ($itemView as $obj)
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex flex-column">
|
||||
<a href="#" class="text-gray-800 text-hover-primary mb-1">
|
||||
<video controls class="h-100px" style="height: 150px!important;">
|
||||
<source src="{{ env('R2_SCHEMA_URL') . $obj['name'] }}"
|
||||
type="video/mp4">
|
||||
Your browser does not support the video element.
|
||||
</video>
|
||||
</a>
|
||||
<span>{{ $obj['name'] }}</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
|
||||
<td>
|
||||
{{ Carbon\Carbon::parse($obj['created_at'])->format('d, M Y') }}
|
||||
</td>
|
||||
|
||||
<td class="min-w-100px text-end">
|
||||
|
||||
{{-- Download --}}
|
||||
<a href="{{ env('R2_SCHEMA_URL') . $obj['name'] }}" target="_blank"
|
||||
class="btn btn-sm btn-icon btn-light btn-active-light-primary"
|
||||
type="button" data-bs-toggle="tooltip" aria-label="Coming soon"
|
||||
data-bs-original-title="Coming soon" data-kt-initialized="1">
|
||||
<i class="bi bi-download fs-3"></i>
|
||||
</a>
|
||||
|
||||
{{-- Copy --}}
|
||||
<button type="button" data-action="copy"
|
||||
data-url="{{ env('R2_SCHEMA_URL') . $obj['name'] }}"
|
||||
class="btn btn-sm btn-icon btn-light btn-active-light-primary copy-button">
|
||||
<span class="svg-icon svg-icon-2">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.5"
|
||||
d="M18 2H9C7.34315 2 6 3.34315 6 5H8C8 4.44772 8.44772 4 9 4H18C18.5523 4 19 4.44772 19 5V16C19 16.5523 18.5523 17 18 17V19C19.6569 19 21 17.6569 21 16V5C21 3.34315 19.6569 2 18 2Z"
|
||||
fill="currentColor"></path>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M14.7857 7.125H6.21429C5.62255 7.125 5.14286 7.6007 5.14286 8.1875V18.8125C5.14286 19.3993 5.62255 19.875 6.21429 19.875H14.7857C15.3774 19.875 15.8571 19.3993 15.8571 18.8125V8.1875C15.8571 7.6007 15.3774 7.125 14.7857 7.125ZM6.21429 5C4.43908 5 3 6.42709 3 8.1875V18.8125C3 20.5729 4.43909 22 6.21429 22H14.7857C16.5609 22 18 20.5729 18 18.8125V8.1875C18 6.42709 16.5609 5 14.7857 5H6.21429Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<!--end::Svg Icon-->
|
||||
</button>
|
||||
|
||||
|
||||
{{-- Delete --}}
|
||||
@if (Auth::user()->role != 2)
|
||||
<a href="#" data-id="{{ $obj['id'] }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm delete-item">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5 9C5 8.44772 5.44772 8 6 8H18C18.5523 8 19 8.44772 19 9V18C19 19.6569 17.6569 21 16 21H8C6.34315 21 5 19.6569 5 18V9Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M5 5C5 4.44772 5.44772 4 6 4H18C18.5523 4 19 4.44772 19 5V5C19 5.55228 18.5523 6 18 6H6C5.44772 6 5 5.55228 5 5V5Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M9 4C9 3.44772 9.44772 3 10 3H14C14.5523 3 15 3.44772 15 4V4H9V4Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
const baseUrl = "{{ url('video') }}";
|
||||
var datatable;
|
||||
datatable = $("#data-table").DataTable({
|
||||
"info": false,
|
||||
"order": [],
|
||||
"pageLength": 25,
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, 500, 1000],
|
||||
[10, 25, 50, 100, 500, 1000]
|
||||
]
|
||||
});
|
||||
|
||||
// Filter by search
|
||||
const filterSearch = document.querySelector('[table-filter="search"]');
|
||||
filterSearch.addEventListener('keyup', function(e) {
|
||||
datatable.search(e.target.value).draw();
|
||||
});
|
||||
|
||||
// filter by status
|
||||
const filterStatus = document.querySelector('[table-filter="status"]');
|
||||
$(filterStatus).on('change', e => {
|
||||
let value = e.target.value;
|
||||
if (value === 'all') {
|
||||
value = '';
|
||||
}
|
||||
datatable.column(4).search(value).draw();
|
||||
});
|
||||
|
||||
|
||||
// Remove
|
||||
$(document).on('click', '.delete-item', function() {
|
||||
swal.fire({
|
||||
allowOutsideClick: false,
|
||||
text: "Are you sure you would like to Delete?",
|
||||
icon: "warning",
|
||||
buttonsStyling: false,
|
||||
showDenyButton: true,
|
||||
confirmButtonText: "Yes",
|
||||
denyButtonText: 'No',
|
||||
customClass: {
|
||||
confirmButton: "btn btn-primary",
|
||||
denyButton: "btn btn-light-danger"
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
// set up ajax
|
||||
initAjaxSetupToken();
|
||||
|
||||
const ajaxProp = {
|
||||
url: "{{ url('video/delete') }}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
item_id: $(this).data('id')
|
||||
},
|
||||
};
|
||||
|
||||
//const id = $(this).data('id');
|
||||
const id = "{{ $folderView->id }}";
|
||||
|
||||
$.ajax(ajaxProp).done(function(res) {
|
||||
if (res.status) {
|
||||
const url = "{{ url('video/folder') }}/" + id;
|
||||
alertSuccessWithUrl('Notice', "Delete success", url);
|
||||
hideLoading();
|
||||
} else {
|
||||
alertFail('Notice', res.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
logAjaxError(xhr, status, error);
|
||||
alertFail('Notice', error.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const copyButtons = document.querySelectorAll('.copy-button');
|
||||
|
||||
copyButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
const urlToCopy = button.getAttribute('data-url');
|
||||
|
||||
// Copy the URL to the clipboard
|
||||
navigator.clipboard.writeText(urlToCopy).then(() => {
|
||||
alert(
|
||||
'Link copied to clipboard!'
|
||||
); // You can change this to a toast notification
|
||||
}).catch(err => {
|
||||
console.error('Could not copy text: ', err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,440 @@
|
||||
@extends('layouts.backendTemplate')
|
||||
|
||||
@section('content')
|
||||
|
||||
<style>
|
||||
.link-container {
|
||||
display: flex;
|
||||
/* Use flexbox for alignment */
|
||||
align-items: center;
|
||||
/* Center items vertically */
|
||||
justify-content: space-between;
|
||||
/* Space between the URL and button */
|
||||
}
|
||||
|
||||
.file-url {
|
||||
flex: 1;
|
||||
/* Allow the URL to take up available space */
|
||||
color: #007bff;
|
||||
/* Link color */
|
||||
text-decoration: none;
|
||||
/* Remove underline */
|
||||
overflow: hidden;
|
||||
/* Hide overflow */
|
||||
white-space: nowrap;
|
||||
/* Prevent text wrapping */
|
||||
text-overflow: ellipsis;
|
||||
/* Add ellipsis for overflow */
|
||||
margin-right: 10px;
|
||||
/* Space between text and button */
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--begin::Main-->
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
|
||||
|
||||
@include('uc.breadcrumbList', [
|
||||
'title' => 'Video Management',
|
||||
'pageName' => 'Video Management',
|
||||
])
|
||||
|
||||
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
|
||||
<div id="kt_app_content_container" class="app-container container-xxl">
|
||||
|
||||
<div class="card">
|
||||
|
||||
@if (Session::has('messageSuccess'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageSuccess')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Session::has('messageFail'))
|
||||
<div class="card-body">
|
||||
@include('uc/messageFail')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<div class="card-header border-0 pt-6">
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
</div>
|
||||
|
||||
@if (Auth::user()->role != 2)
|
||||
<div class="card-toolbar">
|
||||
|
||||
<div class="d-flex justify-content-end" style="margin-right: 5px;"
|
||||
data-kt-customer-table-toolbar="base">
|
||||
<a href="{{ url('video/add-folder') }}" class="btn btn-light-primary me-3"
|
||||
id="kt_file_manager_new_folder">New
|
||||
Folder</a>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end" data-kt-customer-table-toolbar="base">
|
||||
<a href="{{ url('video/add') }}" class="btn btn-primary">Add </a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card-header border-0 pt-5">
|
||||
|
||||
<div class="card-title">
|
||||
<div class="d-flex align-items-center position-relative my-1">
|
||||
<span class="svg-icon svg-icon-1 position-absolute ms-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<rect opacity="0.5" x="17.0365" y="15.1223" width="8.15546" height="2"
|
||||
rx="1" transform="rotate(45 17.0365 15.1223)" fill="currentColor">
|
||||
</rect>
|
||||
<path
|
||||
d="M11 19C6.55556 19 3 15.4444 3 11C3 6.55556 6.55556 3 11 3C15.4444 3 19 6.55556 19 11C19 15.4444 15.4444 19 11 19ZM11 5C7.53333 5 5 7.53333 5 11C5 14.4667 7.53333 17 11 17C14.4667 17 17 14.4667 17 11C17 7.53333 14.4667 5 11 5Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<input type="text" table-filter="search"
|
||||
class="form-control form-control-solid w-250px ps-15" placeholder="Search" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-body py-4">
|
||||
<!--begin::Table-->
|
||||
<table class="table align-middle table-row-dashed fs-6 gy-5" id="data-table">
|
||||
<!--begin::Table head-->
|
||||
<thead>
|
||||
<!--begin::Table row-->
|
||||
<tr class="text-start text-muted fw-bold fs-7 text-uppercase gs-0">
|
||||
<th class="min-w-125px">Name</th>
|
||||
<th class="min-w-125px">Created</th>
|
||||
<th class="text-end min-w-100px">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="text-gray-600 fw-semibold">
|
||||
|
||||
@foreach ($folderView as $obj)
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<span class="svg-icon svg-icon-2x svg-icon-primary me-4">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3" d="M10 4H21C21.6 4 22 4.4 22 5V7H10V4Z"
|
||||
fill="currentColor"></path>
|
||||
<path
|
||||
d="M9.2 3H3C2.4 3 2 3.4 2 4V19C2 19.6 2.4 20 3 20H21C21.6 20 22 19.6 22 19V7C22 6.4 21.6 6 21 6H12L10.4 3.60001C10.2 3.20001 9.7 3 9.2 3Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<a href="{{ url('video/folder/' . $obj->id) }}"
|
||||
class="text-gray-800 text-hover-primary">
|
||||
{{ $obj->name }}</a>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ Carbon\Carbon::parse($obj['created_at'])->format('d, M Y') }}
|
||||
</td>
|
||||
|
||||
<td class="min-w-100px text-end">
|
||||
|
||||
{{-- Download --}}
|
||||
<a href="{{ url('video/download-folder') . '/' . $obj->id }}"
|
||||
class="btn-download-folder btn btn-sm btn-icon btn-light btn-active-light-primary"
|
||||
type="button" data-bs-toggle="tooltip" aria-label="Coming soon"
|
||||
data-bs-original-title="Coming soon" data-kt-initialized="1">
|
||||
<i class="bi bi-download fs-3"></i>
|
||||
</a>
|
||||
|
||||
|
||||
{{-- Edit --}}
|
||||
<a href="{{ url('video/edit-folder/' . $obj['id']) }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm me-1">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3"
|
||||
d="M21.4 8.35303L19.241 10.511L13.485 4.755L15.643 2.59595C16.0248 2.21423 16.5426 1.99988 17.0825 1.99988C17.6224 1.99988 18.1402 2.21423 18.522 2.59595L21.4 5.474C21.7817 5.85581 21.9962 6.37355 21.9962 6.91345C21.9962 7.45335 21.7817 7.97122 21.4 8.35303ZM3.68699 21.932L9.88699 19.865L4.13099 14.109L2.06399 20.309C1.98815 20.5354 1.97703 20.7787 2.03189 21.0111C2.08674 21.2436 2.2054 21.4561 2.37449 21.6248C2.54359 21.7934 2.75641 21.9115 2.989 21.9658C3.22158 22.0201 3.4647 22.0084 3.69099 21.932H3.68699Z"
|
||||
fill="currentColor" />
|
||||
<path
|
||||
d="M5.574 21.3L3.692 21.928C3.46591 22.0032 3.22334 22.0141 2.99144 21.9594C2.75954 21.9046 2.54744 21.7864 2.3789 21.6179C2.21036 21.4495 2.09202 21.2375 2.03711 21.0056C1.9822 20.7737 1.99289 20.5312 2.06799 20.3051L2.696 18.422L5.574 21.3ZM4.13499 14.105L9.891 19.861L19.245 10.507L13.489 4.75098L4.13499 14.105Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{{-- Delete --}}
|
||||
<a href="#" data-id="{{ $obj['id'] }}"
|
||||
class="btn btn-icon btn-bg-light btn-active-color-primary btn-sm delete-folder-item">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5 9C5 8.44772 5.44772 8 6 8H18C18.5523 8 19 8.44772 19 9V18C19 19.6569 17.6569 21 16 21H8C6.34315 21 5 19.6569 5 18V9Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M5 5C5 4.44772 5.44772 4 6 4H18C18.5523 4 19 4.44772 19 5V5C19 5.55228 18.5523 6 18 6H6C5.44772 6 5 5.55228 5 5V5Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M9 4C9 3.44772 9.44772 3 10 3H14C14.5523 3 15 3.44772 15 4V4H9V4Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
|
||||
@foreach ($itemView as $obj)
|
||||
<tr>
|
||||
|
||||
<td class="d-flex align-items-center">
|
||||
<div class="d-flex flex-column">
|
||||
<a href="#" class="text-gray-800 text-hover-primary mb-1">
|
||||
<video controls class="h-100px" style="height: 150px!important;">
|
||||
<source src="{{ env('R2_SCHEMA_URL') . $obj['name'] }}"
|
||||
type="video/mp4">
|
||||
Your browser does not support the video element.
|
||||
</video>
|
||||
</a>
|
||||
<span>{{ $obj['name'] }}</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ Carbon\Carbon::parse($obj['created_at'])->format('d, M Y') }}
|
||||
</td>
|
||||
|
||||
<td class="min-w-100px text-end">
|
||||
|
||||
{{-- Download --}}
|
||||
<a href="{{ env('R2_SCHEMA_URL') . $obj['name'] }}" target="_blank"
|
||||
class="btn btn-sm btn-icon btn-light btn-active-light-primary"
|
||||
type="button" data-bs-toggle="tooltip" aria-label="Coming soon"
|
||||
data-bs-original-title="Coming soon" data-kt-initialized="1">
|
||||
<i class="bi bi-download fs-3"></i>
|
||||
</a>
|
||||
|
||||
{{-- Copy --}}
|
||||
<button type="button" data-action="copy"
|
||||
data-url="{{ env('R2_SCHEMA_URL') . $obj['name'] }}"
|
||||
class="btn btn-sm btn-icon btn-light btn-active-light-primary copy-button">
|
||||
<span class="svg-icon svg-icon-2">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.5"
|
||||
d="M18 2H9C7.34315 2 6 3.34315 6 5H8C8 4.44772 8.44772 4 9 4H18C18.5523 4 19 4.44772 19 5V16C19 16.5523 18.5523 17 18 17V19C19.6569 19 21 17.6569 21 16V5C21 3.34315 19.6569 2 18 2Z"
|
||||
fill="currentColor"></path>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M14.7857 7.125H6.21429C5.62255 7.125 5.14286 7.6007 5.14286 8.1875V18.8125C5.14286 19.3993 5.62255 19.875 6.21429 19.875H14.7857C15.3774 19.875 15.8571 19.3993 15.8571 18.8125V8.1875C15.8571 7.6007 15.3774 7.125 14.7857 7.125ZM6.21429 5C4.43908 5 3 6.42709 3 8.1875V18.8125C3 20.5729 4.43909 22 6.21429 22H14.7857C16.5609 22 18 20.5729 18 18.8125V8.1875C18 6.42709 16.5609 5 14.7857 5H6.21429Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<!--end::Svg Icon-->
|
||||
</button>
|
||||
|
||||
{{-- Delete --}}
|
||||
@if (Auth::user()->role != 2)
|
||||
<a href="#" data-id="{{ $obj['id'] }}"
|
||||
class="btn btn-sm btn-icon btn-light btn-active-light-primary delete-item">
|
||||
<span class="svg-icon svg-icon-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24"
|
||||
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5 9C5 8.44772 5.44772 8 6 8H18C18.5523 8 19 8.44772 19 9V18C19 19.6569 17.6569 21 16 21H8C6.34315 21 5 19.6569 5 18V9Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M5 5C5 4.44772 5.44772 4 6 4H18C18.5523 4 19 4.44772 19 5V5C19 5.55228 18.5523 6 18 6H6C5.44772 6 5 5.55228 5 5V5Z"
|
||||
fill="currentColor" />
|
||||
<path opacity="0.5"
|
||||
d="M9 4C9 3.44772 9.44772 3 10 3H14C14.5523 3 15 3.44772 15 4V4H9V4Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('script')
|
||||
|
||||
<script type="text/javascript">
|
||||
const baseUrl = "{{ url('video') }}";
|
||||
var datatable;
|
||||
datatable = $("#data-table").DataTable({
|
||||
"info": false,
|
||||
"order": [],
|
||||
"pageLength": 25,
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, 500, 1000],
|
||||
[10, 25, 50, 100, 500, 1000]
|
||||
]
|
||||
});
|
||||
|
||||
// Filter by search
|
||||
const filterSearch = document.querySelector('[table-filter="search"]');
|
||||
filterSearch.addEventListener('keyup', function(e) {
|
||||
datatable.search(e.target.value).draw();
|
||||
});
|
||||
|
||||
// filter by status
|
||||
const filterStatus = document.querySelector('[table-filter="status"]');
|
||||
$(filterStatus).on('change', e => {
|
||||
let value = e.target.value;
|
||||
if (value === 'all') {
|
||||
value = '';
|
||||
}
|
||||
datatable.column(4).search(value).draw();
|
||||
});
|
||||
|
||||
|
||||
// Remove
|
||||
$(document).on('click', '.delete-item', function() {
|
||||
swal.fire({
|
||||
allowOutsideClick: false,
|
||||
text: "Are you sure you would like to Delete?",
|
||||
icon: "warning",
|
||||
buttonsStyling: false,
|
||||
showDenyButton: true,
|
||||
confirmButtonText: "Yes",
|
||||
denyButtonText: 'No',
|
||||
customClass: {
|
||||
confirmButton: "btn btn-primary",
|
||||
denyButton: "btn btn-light-danger"
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
// set up ajax
|
||||
initAjaxSetupToken();
|
||||
|
||||
const ajaxProp = {
|
||||
url: "{{ url('video/delete') }}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
item_id: $(this).data('id')
|
||||
},
|
||||
};
|
||||
|
||||
$.ajax(ajaxProp).done(function(res) {
|
||||
if (res.status) {
|
||||
const url = "{{ url('video') }}";
|
||||
alertSuccessWithUrl('Notice', "Delete success", url);
|
||||
hideLoading();
|
||||
} else {
|
||||
alertFail('Notice', res.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
logAjaxError(xhr, status, error);
|
||||
alertFail('Notice', error.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const copyButtons = document.querySelectorAll('.copy-button');
|
||||
|
||||
copyButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
const urlToCopy = button.getAttribute('data-url');
|
||||
|
||||
// Copy the URL to the clipboard
|
||||
navigator.clipboard.writeText(urlToCopy).then(() => {
|
||||
alert(
|
||||
'Link copied to clipboard!'
|
||||
); // You can change this to a toast notification
|
||||
}).catch(err => {
|
||||
console.error('Could not copy text: ', err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Delete folder
|
||||
$(document).on('click', '.delete-folder-item', function() {
|
||||
swal.fire({
|
||||
allowOutsideClick: false,
|
||||
text: "Are you sure you would like to Delete?",
|
||||
icon: "warning",
|
||||
buttonsStyling: false,
|
||||
showDenyButton: true,
|
||||
confirmButtonText: "Yes",
|
||||
denyButtonText: 'No',
|
||||
customClass: {
|
||||
confirmButton: "btn btn-primary",
|
||||
denyButton: "btn btn-light-danger"
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
|
||||
alertLoading("Loading")
|
||||
|
||||
// set up ajax
|
||||
initAjaxSetupToken();
|
||||
|
||||
const ajaxProp = {
|
||||
url: "{{ url('video/delete-folder') }}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
item_id: $(this).data('id')
|
||||
},
|
||||
};
|
||||
|
||||
$.ajax(ajaxProp).done(function(res) {
|
||||
if (res.status) {
|
||||
const url = "{{ url('video') }}";
|
||||
alertSuccessWithUrl('Notice', "Delete success", url);
|
||||
hideLoading();
|
||||
} else {
|
||||
alertFail('Notice', res.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
logAjaxError(xhr, status, error);
|
||||
alertFail('Notice', error.message ?? "Unsuccessfully");
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
Reference in New Issue
Block a user