Merge branch 'main' of https://git.project-pro.pl/Project-Pro/crmPRO
This commit is contained in:
92
.vscode/ftp-kr.sync.cache.json
vendored
92
.vscode/ftp-kr.sync.cache.json
vendored
@@ -121,8 +121,8 @@
|
||||
},
|
||||
"class.Tasks.php": {
|
||||
"type": "-",
|
||||
"size": 24179,
|
||||
"lmtime": 1771336367894,
|
||||
"size": 25433,
|
||||
"lmtime": 1771495209476,
|
||||
"modified": false
|
||||
},
|
||||
"class.Users.php": {
|
||||
@@ -164,14 +164,14 @@
|
||||
},
|
||||
"MailToTaskImporter.php": {
|
||||
"type": "-",
|
||||
"size": 37982,
|
||||
"lmtime": 1770800891666,
|
||||
"size": 56836,
|
||||
"lmtime": 1771496082257,
|
||||
"modified": false
|
||||
},
|
||||
"TaskAttachmentRepository.php": {
|
||||
"type": "-",
|
||||
"size": 8806,
|
||||
"lmtime": 1770731454505,
|
||||
"size": 11955,
|
||||
"lmtime": 1771496082258,
|
||||
"modified": false
|
||||
},
|
||||
"WorkTimeRepository.php": {
|
||||
@@ -251,11 +251,17 @@
|
||||
".claude": {
|
||||
"settings.local.json": {
|
||||
"type": "-",
|
||||
"size": 449,
|
||||
"lmtime": 1771336223831,
|
||||
"size": 452,
|
||||
"lmtime": 1771422306144,
|
||||
"modified": false
|
||||
}
|
||||
},
|
||||
"CLAUDE.md": {
|
||||
"type": "-",
|
||||
"size": 4572,
|
||||
"lmtime": 1771422482909,
|
||||
"modified": false
|
||||
},
|
||||
"CODE_INDEX.md": {
|
||||
"type": "-",
|
||||
"size": 16884,
|
||||
@@ -264,7 +270,7 @@
|
||||
},
|
||||
"config.php": {
|
||||
"type": "-",
|
||||
"size": 1232,
|
||||
"size": 1186,
|
||||
"lmtime": 1770587027872,
|
||||
"modified": true
|
||||
},
|
||||
@@ -294,6 +300,12 @@
|
||||
"lmtime": 1770733260000,
|
||||
"modified": true
|
||||
},
|
||||
"mail_import_debug.log": {
|
||||
"type": "-",
|
||||
"size": 18628,
|
||||
"lmtime": 0,
|
||||
"modified": false
|
||||
},
|
||||
"REFACTORING_PLAN.md": {
|
||||
"type": "-",
|
||||
"size": 3576,
|
||||
@@ -323,20 +335,20 @@
|
||||
},
|
||||
"main_view.php": {
|
||||
"type": "-",
|
||||
"size": 42784,
|
||||
"size": 41808,
|
||||
"lmtime": 1771336223833,
|
||||
"modified": false
|
||||
"modified": true
|
||||
},
|
||||
"task_edit.php": {
|
||||
"type": "-",
|
||||
"size": 10758,
|
||||
"lmtime": 1771237304287,
|
||||
"size": 29190,
|
||||
"lmtime": 1771495910826,
|
||||
"modified": false
|
||||
},
|
||||
"task_popup.php": {
|
||||
"type": "-",
|
||||
"size": 22706,
|
||||
"lmtime": 1771336355877,
|
||||
"size": 22823,
|
||||
"lmtime": 1771426296050,
|
||||
"modified": false
|
||||
},
|
||||
"task_single.php": {
|
||||
@@ -466,22 +478,66 @@
|
||||
"lmtime": 1770653587539,
|
||||
"modified": false
|
||||
}
|
||||
},
|
||||
"Tasks": {
|
||||
"MailToTaskImporterTest.php": {
|
||||
"type": "-",
|
||||
"size": 3494,
|
||||
"lmtime": 1771496082259,
|
||||
"modified": false
|
||||
},
|
||||
"TaskAttachmentRepositoryTest.php": {
|
||||
"type": "-",
|
||||
"size": 1728,
|
||||
"lmtime": 1771496082260,
|
||||
"modified": false
|
||||
},
|
||||
"WorkTimeRepositoryTest.php": {
|
||||
"type": "-",
|
||||
"size": 1913,
|
||||
"lmtime": 0,
|
||||
"modified": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"run.php": {
|
||||
"type": "-",
|
||||
"size": 851,
|
||||
"lmtime": 1770653605021,
|
||||
"size": 970,
|
||||
"lmtime": 1771496082261,
|
||||
"modified": false
|
||||
}
|
||||
},
|
||||
"_tmp_db_check.php": {
|
||||
"type": "-",
|
||||
"size": 696,
|
||||
"lmtime": 0,
|
||||
"modified": false
|
||||
},
|
||||
"tmp_debug_mail_import.php": {
|
||||
"type": "-",
|
||||
"size": 1238,
|
||||
"lmtime": 0,
|
||||
"modified": false
|
||||
},
|
||||
"upload": {}
|
||||
"_tmp_mail_name_check.php": {
|
||||
"type": "-",
|
||||
"size": 62,
|
||||
"lmtime": 0,
|
||||
"modified": false
|
||||
},
|
||||
"TODO.md": {
|
||||
"type": "-",
|
||||
"size": 103,
|
||||
"lmtime": 1771423099316,
|
||||
"modified": false
|
||||
},
|
||||
"upload": {},
|
||||
"VIDOK_Instrukcja Montażu I Uruchomienia - Wyroby Elektryczne.pdf": {
|
||||
"type": "-",
|
||||
"size": 230708,
|
||||
"lmtime": 1771496082255,
|
||||
"modified": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"$version": 1
|
||||
|
||||
@@ -362,6 +362,8 @@ class Tasks
|
||||
}
|
||||
|
||||
$task_id = (int)\S::get( 'task_id' );
|
||||
if ( !$task_id )
|
||||
$task_id = (int)\S::get( 'id' );
|
||||
$users = \S::get( 'users' );
|
||||
$status_change_mail_value = \S::get( 'status_change_mail' );
|
||||
$status_change_mail = 0;
|
||||
@@ -432,13 +434,24 @@ class Tasks
|
||||
exit;
|
||||
}
|
||||
|
||||
$task = \factory\Tasks::task_details( \S::get( 'task_id' ) );
|
||||
$task_id = (int)\S::get( 'task_id' );
|
||||
if ( !$task_id )
|
||||
$task_id = (int)\S::get( 'id' );
|
||||
|
||||
$attachments_repository = new \Domain\Tasks\TaskAttachmentRepository();
|
||||
$task = \factory\Tasks::task_details( $task_id );
|
||||
if ( !is_array( $task ) )
|
||||
$task = [];
|
||||
|
||||
$task['status'] = \Controllers\TasksController::resolveTaskStatusForForm( $task );
|
||||
$task['id'] = isset( $task['id'] ) ? (int)$task['id'] : $task_id;
|
||||
$task_id_for_attachments = (int)$task['id'];
|
||||
|
||||
return \Tpl::view( 'tasks/task_edit', [
|
||||
'projects' => \factory\Projects::user_projects( $user['id'] ),
|
||||
'priorities' => \factory\Tasks::$priorities,
|
||||
'task' => $task,
|
||||
'task_attachments' => $task_id_for_attachments ? $attachments_repository -> listByTaskId( $task_id_for_attachments ) : [],
|
||||
'parent_tasks' => \factory\Tasks::parent_tasks( $user['id'] ),
|
||||
'users' => \factory\Users::users_list(),
|
||||
'clients' => \factory\Crm::get_client_list(),
|
||||
@@ -616,6 +629,35 @@ class Tasks
|
||||
exit;
|
||||
}
|
||||
|
||||
static public function task_attachments_list()
|
||||
{
|
||||
global $user;
|
||||
|
||||
if ( !$user )
|
||||
{
|
||||
header( 'Location: /logowanie' );
|
||||
exit;
|
||||
}
|
||||
|
||||
$task_id = (int)\S::get( 'task_id' );
|
||||
|
||||
if ( !$task_id )
|
||||
{
|
||||
echo json_encode( [ 'status' => 'error', 'msg' => 'Brak identyfikatora zadania.' ] );
|
||||
exit;
|
||||
}
|
||||
|
||||
$repository = new \Domain\Tasks\TaskAttachmentRepository();
|
||||
$attachments = $repository -> listByTaskId( $task_id );
|
||||
|
||||
echo json_encode( [
|
||||
'status' => 'success',
|
||||
'attachments' => is_array( $attachments ) ? $attachments : [],
|
||||
'count' => is_array( $attachments ) ? count( $attachments ) : 0
|
||||
] );
|
||||
exit;
|
||||
}
|
||||
|
||||
static public function filtr_save_form() {
|
||||
echo json_encode( [
|
||||
'status' => 'success',
|
||||
|
||||
@@ -1,6 +1,45 @@
|
||||
<?
|
||||
global $db;
|
||||
|
||||
$task_id = (int)$this -> task['id'];
|
||||
$task_attachments = ( isset( $this -> task_attachments ) and is_array( $this -> task_attachments ) ) ? $this -> task_attachments : [];
|
||||
$attachments_count = count( $task_attachments );
|
||||
|
||||
$date_start = '';
|
||||
if ( $this -> task['date_start'] )
|
||||
$date_start = date( 'Y-m-d', strtotime( $this -> task['date_start'] ) );
|
||||
elseif ( !$this -> task['id'] )
|
||||
$date_start = date( 'Y-m-d' );
|
||||
|
||||
$date_end = '';
|
||||
if ( $this -> task['date_end'] )
|
||||
$date_end = date( 'Y-m-d', strtotime( $this -> task['date_end'] ) );
|
||||
elseif ( !$this -> task['id'] )
|
||||
$date_end = date( 'Y-m-d' );
|
||||
|
||||
$projects = [ 0 => '--- wybierz projekt ---' ];
|
||||
if ( is_array( $this -> projects ) )
|
||||
foreach ( $this -> projects as $project )
|
||||
{
|
||||
$projects[ $project[ 'id' ] ] = $project[ 'name' ];
|
||||
if ( (int)$project['client_id'] )
|
||||
$projects[ $project['id'] ] .= ' (' . \factory\Crm::get_client_name( (int)$project[ 'client_id' ] ) . ')';
|
||||
}
|
||||
|
||||
$project_id = $this -> task['project_id'] ? $this -> task[ 'project_id' ] : 0;
|
||||
if ( !$this -> task['id'] and !$project_id )
|
||||
$project_id = 72;
|
||||
|
||||
$clients = [ 0 => '--- wybierz klienta ---' ];
|
||||
if ( is_array( $this -> clients ) )
|
||||
foreach ( $this -> clients as $client )
|
||||
$clients[ $client[ 'id' ] ] = $client[ 'firm' ];
|
||||
|
||||
$parent_tasks = [ 0 => '--- wybierz zadanie nadrzędne ---' ];
|
||||
if ( is_array( $this -> parent_tasks ) )
|
||||
foreach ( $this -> parent_tasks as $parent_task )
|
||||
$parent_tasks[ $parent_task[ 'id' ] ] = $parent_task[ 'name' ] . ( $parent_task['client'] ? ' (' . $parent_task['client'] . ')' : '' );
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<?=
|
||||
@@ -28,21 +67,9 @@ ob_start();
|
||||
);
|
||||
?>
|
||||
<?
|
||||
if ( $this -> task['date_start'] )
|
||||
$date_start = date( 'Y-m-d', strtotime( $this -> task['date_start'] ) );
|
||||
else
|
||||
{
|
||||
if ( !$this -> task['id'] )
|
||||
$date_start = date( 'Y-m-d' );
|
||||
}
|
||||
$tab_basic = ob_get_clean();
|
||||
|
||||
if ( $this -> task['date_end'] )
|
||||
$date_end = date( 'Y-m-d', strtotime( $this -> task['date_end'] ) );
|
||||
else
|
||||
{
|
||||
if ( !$this -> task['id'] )
|
||||
$date_end = date( 'Y-m-d' );
|
||||
}
|
||||
ob_start();
|
||||
?>
|
||||
<?= \Html::input([
|
||||
'label' => 'Data rozpoczęcia',
|
||||
@@ -62,25 +89,6 @@ else
|
||||
'inline' => true,
|
||||
'autocomplete' => 'off'
|
||||
]);?>
|
||||
<?
|
||||
$projects[ 0 ] = '--- wybierz projekt ---';
|
||||
if ( is_array( $this -> projects ) )
|
||||
foreach ( $this -> projects as $project )
|
||||
{
|
||||
$projects[ $project[ 'id' ] ] = $project[ 'name' ];
|
||||
if ( (int)$project['client_id'] )
|
||||
$projects[ $project['id'] ] .= ' (' . \factory\Crm::get_client_name( (int)$project[ 'client_id' ] ) . ')';
|
||||
}
|
||||
?>
|
||||
<?
|
||||
if ( $this -> task['project_id'] )
|
||||
$project_id = $this -> task[ 'project_id' ];
|
||||
else
|
||||
{
|
||||
if ( !$this -> task['id'] )
|
||||
$project_id = 72;
|
||||
}
|
||||
?>
|
||||
<?= \Html::select([
|
||||
'label' => 'Projekt',
|
||||
'name' => 'project_id',
|
||||
@@ -88,12 +96,6 @@ else
|
||||
'value' => $project_id,
|
||||
'values' => $projects
|
||||
]);?>
|
||||
<?
|
||||
$clients[ 0 ] = '--- wybierz klienta ---';
|
||||
if ( is_array( $this -> clients ) )
|
||||
foreach ( $this -> clients as $client )
|
||||
$clients[ $client[ 'id' ] ] = $client[ 'firm' ];
|
||||
?>
|
||||
<?=
|
||||
\Html::select( [
|
||||
'label' => 'Klient',
|
||||
@@ -103,14 +105,7 @@ if ( is_array( $this -> clients ) )
|
||||
'values' => $clients
|
||||
] );
|
||||
?>
|
||||
<!-- zadanie nadrzędne -->
|
||||
<?
|
||||
$parent_tasks[ 0 ] = '--- wybierz zadanie nadrzędne ---';
|
||||
if ( is_array( $this -> parent_tasks ) )
|
||||
foreach ( $this -> parent_tasks as $parent_task )
|
||||
$parent_tasks[ $parent_task[ 'id' ] ] = $parent_task[ 'name' ] . ( $parent_task['client'] ? ' (' . $parent_task['client'] . ')' : '' );
|
||||
?>
|
||||
<?
|
||||
<?=
|
||||
\Html::select( [
|
||||
'label' => 'Zadanie nadrzędne',
|
||||
'name' => 'parent_id',
|
||||
@@ -126,13 +121,6 @@ if ( is_array( $this -> parent_tasks ) )
|
||||
'value' => $this -> task[ 'id' ] ? $this -> task[ 'status' ] : 5,
|
||||
'values' => \factory\Tasks::get_statuses()
|
||||
] );?>
|
||||
<!-- priorytet -->
|
||||
<?
|
||||
$priorities[ 0 ] = '--- wybierz priorytet ---';
|
||||
if ( is_array( $this -> priorities ) )
|
||||
foreach ( $this -> priorities as $priority )
|
||||
$priorities[ $priority[ 'id' ] ] = $priority[ 'name' ];
|
||||
?>
|
||||
<?=
|
||||
\Html::select( [
|
||||
'label' => 'Priorytet',
|
||||
@@ -153,6 +141,11 @@ if ( is_array( $this -> priorities ) )
|
||||
'autocomplete' => 'off'
|
||||
]);?>
|
||||
<? endif;?>
|
||||
<?
|
||||
$tab_details = ob_get_clean();
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<?=
|
||||
\Html::input_switch( [
|
||||
'label' => 'Powiadom o zmianie statusu',
|
||||
@@ -239,8 +232,243 @@ if ( is_array( $this -> priorities ) )
|
||||
</div>
|
||||
<? endif;?>
|
||||
<?
|
||||
$this -> task[ 'id' ] ? $project_id = $this -> task[ 'project_id' ] : $project_id = $this -> project_id;
|
||||
$tab_users_and_automation = ob_get_clean();
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="task-edit-attachments" data-task-id="<?= $task_id;?>">
|
||||
<div class="attachments-requires-save" <? if ( $task_id ):?>style="display: none;"<? endif;?>>
|
||||
<div class="alert alert-info" style="margin-bottom: 12px;">
|
||||
Najpierw zapisz zadanie, aby dodać załączniki.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="attachments-ready" <? if ( !$task_id ):?>style="display: none;"<? endif;?>>
|
||||
<div class="attachments_upload" style="margin-bottom: 12px; display: flex; gap: 8px; align-items: center; flex-wrap: wrap;">
|
||||
<input type="file" class="form-control attachment_file_input" name="attachments[]" multiple style="max-width: 420px;">
|
||||
<a href="#" class="attachment-upload-btn btn btn-primary btn-sm" task_id="<?= $task_id;?>">Dodaj załączniki</a>
|
||||
</div>
|
||||
<ul class="attachments_list" style="list-style: none; padding-left: 0; margin-left: 0;">
|
||||
<? if ( is_array( $task_attachments ) and count( $task_attachments ) ):?>
|
||||
<? foreach ( $task_attachments as $attachment ):?>
|
||||
<li class="attachment-item">
|
||||
<a href="<?= $attachment['url'];?>" target="_blank" rel="noopener noreferrer" class="attachment-link" download="<?= htmlspecialchars( $attachment['title_effective'] );?>">
|
||||
<?= htmlspecialchars( $attachment['title_effective'] );?>
|
||||
</a>
|
||||
<small>(<?= $attachment['size_human'];?>)</small>
|
||||
<a href="#" class="attachment-rename" attachment_id="<?= $attachment['id'];?>" title_current="<?= htmlspecialchars( $attachment['title_effective'] );?>"><i class="fa fa-pencil"></i></a>
|
||||
<a href="#" class="attachment-delete" attachment_id="<?= $attachment['id'];?>"><i class="fa fa-trash"></i></a>
|
||||
</li>
|
||||
<? endforeach;?>
|
||||
<? else:?>
|
||||
<li class="attachments-empty">Brak załączników.</li>
|
||||
<? endif;?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<?
|
||||
$tab_attachments = ob_get_clean();
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div id="task-edit-tabs" class="task-edit-tabs" data-task-id="<?= $task_id;?>">
|
||||
<div class="task-tabs-nav" role="tablist" aria-label="Przełącz zakładkę edycji zadania">
|
||||
<a href="#" class="js-task-edit-tab-btn is-active" data-tab="basic" role="tab" aria-selected="true">Podstawowe</a>
|
||||
<a href="#" class="js-task-edit-tab-btn" data-tab="details" role="tab" aria-selected="false">Szczegóły</a>
|
||||
<a href="#" class="js-task-edit-tab-btn" data-tab="users_automation" role="tab" aria-selected="false">Uczestnicy i automatyzacja</a>
|
||||
<a href="#" class="js-task-edit-tab-btn js-attachments-tab-btn" data-tab="attachments" role="tab" aria-selected="false">Załączniki (<?= (int)$attachments_count;?>)</a>
|
||||
</div>
|
||||
|
||||
<div class="task-edit-tab-panel is-active" data-tab="basic">
|
||||
<?= $tab_basic;?>
|
||||
</div>
|
||||
<div class="task-edit-tab-panel" data-tab="details">
|
||||
<?= $tab_details;?>
|
||||
</div>
|
||||
<div class="task-edit-tab-panel" data-tab="users_automation">
|
||||
<?= $tab_users_and_automation;?>
|
||||
</div>
|
||||
<div class="task-edit-tab-panel" data-tab="attachments">
|
||||
<?= $tab_attachments;?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style type="text/css">
|
||||
.task-edit-tabs .task-tabs-nav {
|
||||
margin: 0 0 16px 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
border: 1px solid #d8e2f6;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: #f4f8ff;
|
||||
}
|
||||
|
||||
.task-edit-tabs .task-tabs-nav .js-task-edit-tab-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 38px;
|
||||
padding: 8px 14px;
|
||||
color: #355899;
|
||||
text-decoration: none;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
border-right: 1px solid #d8e2f6;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.task-edit-tabs .task-tabs-nav .js-task-edit-tab-btn:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
.task-edit-tabs .task-tabs-nav .js-task-edit-tab-btn:hover {
|
||||
background: #e7f0ff;
|
||||
color: #274985;
|
||||
}
|
||||
|
||||
.task-edit-tabs .task-tabs-nav .js-task-edit-tab-btn.is-active {
|
||||
background: #6690f4;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.task-edit-tabs .task-edit-tab-panel {
|
||||
display: none;
|
||||
padding: 6px 2px 2px 2px;
|
||||
}
|
||||
|
||||
.task-edit-tabs .task-edit-tab-panel.is-active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.task-edit-attachments .attachments_list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.task-edit-attachments .attachments_list li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
background: #fff;
|
||||
border: 1px solid #e4e8ee;
|
||||
border-radius: 6px;
|
||||
padding: 8px 10px;
|
||||
}
|
||||
|
||||
.task-edit-attachments .attachments_list li .attachment-link {
|
||||
color: #1f3d72;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: calc(100% - 140px);
|
||||
}
|
||||
|
||||
.task-edit-attachments .attachments_list li .attachment-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.task-edit-attachments .attachments_list li small {
|
||||
color: #6b7280;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.task-edit-attachments .attachments_list li .attachment-rename,
|
||||
.task-edit-attachments .attachments_list li .attachment-delete {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.task-edit-attachments .attachments_list li .attachment-rename {
|
||||
border: 1px solid #d8e2f6;
|
||||
color: #6690f4;
|
||||
background: #f4f8ff;
|
||||
}
|
||||
|
||||
.task-edit-attachments .attachments_list li .attachment-rename:hover {
|
||||
background: #e7f0ff;
|
||||
}
|
||||
|
||||
.task-edit-attachments .attachments_list li .attachment-delete {
|
||||
border: 1px solid #f1d3d1;
|
||||
color: #cc563d;
|
||||
background: #fff6f6;
|
||||
}
|
||||
|
||||
.task-edit-attachments .attachments_list li .attachment-delete:hover {
|
||||
background: #ffeaea;
|
||||
}
|
||||
|
||||
.task-edit-attachments .attachments_list .attachments-empty {
|
||||
color: #6b7280;
|
||||
border-style: dashed;
|
||||
justify-content: center;
|
||||
font-size: 13px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.task-edit-message {
|
||||
margin: 12px 0 16px 0;
|
||||
padding: 12px 16px;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
animation: slideDown 0.3s ease;
|
||||
border-left: 4px solid;
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.task-edit-message.alert-success {
|
||||
background-color: #d4edda;
|
||||
border-color: #28a745;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.task-edit-message.alert-danger {
|
||||
background-color: #f8d7da;
|
||||
border-color: #dc3545;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
.task-edit-message i {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
@media (max-width: 991px) {
|
||||
.task-edit-tabs .task-tabs-nav .js-task-edit-tab-btn {
|
||||
flex: 1 1 50%;
|
||||
border-right: 0;
|
||||
border-bottom: 1px solid #d8e2f6;
|
||||
}
|
||||
|
||||
.task-edit-tabs .task-tabs-nav .js-task-edit-tab-btn:nth-last-child(-n+2) {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<?
|
||||
$out = ob_get_clean();
|
||||
|
||||
$grid = new \gridEdit;
|
||||
@@ -269,6 +497,49 @@ echo $grid -> draw();
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function ()
|
||||
{
|
||||
var task_edit_root = $( '#task-edit-tabs' );
|
||||
var task_edit_tab_storage_key = 'crm_task_edit_active_tab';
|
||||
|
||||
function setActiveTaskEditTab( tab_name ) {
|
||||
var panels = task_edit_root.find( '.task-edit-tab-panel' );
|
||||
var buttons = task_edit_root.find( '.js-task-edit-tab-btn' );
|
||||
|
||||
if ( !panels.length )
|
||||
return;
|
||||
|
||||
var allowed_tabs = [ 'basic', 'details', 'users_automation', 'attachments' ];
|
||||
var selected_tab = allowed_tabs.indexOf( tab_name ) >= 0 ? tab_name : 'basic';
|
||||
|
||||
panels.each( function() {
|
||||
var panel = $( this );
|
||||
panel.toggleClass( 'is-active', panel.attr( 'data-tab' ) === selected_tab );
|
||||
});
|
||||
|
||||
buttons.each( function() {
|
||||
var button = $( this );
|
||||
var is_active = button.attr( 'data-tab' ) === selected_tab;
|
||||
button.toggleClass( 'is-active', is_active ).attr( 'aria-selected', is_active ? 'true' : 'false' );
|
||||
});
|
||||
|
||||
window.crm_task_edit_active_tab = selected_tab;
|
||||
if ( window.sessionStorage )
|
||||
window.sessionStorage.setItem( task_edit_tab_storage_key, selected_tab );
|
||||
}
|
||||
|
||||
task_edit_root.on( 'click', '.js-task-edit-tab-btn', function( e ) {
|
||||
e.preventDefault();
|
||||
setActiveTaskEditTab( $( this ).attr( 'data-tab' ) );
|
||||
} );
|
||||
|
||||
var remembered_task_edit_tab = window.crm_task_edit_active_tab || 'basic';
|
||||
if ( window.sessionStorage )
|
||||
{
|
||||
var stored_tab = window.sessionStorage.getItem( task_edit_tab_storage_key );
|
||||
if ( stored_tab )
|
||||
remembered_task_edit_tab = stored_tab;
|
||||
}
|
||||
setActiveTaskEditTab( remembered_task_edit_tab );
|
||||
|
||||
function toggleRecursiveDetails() {
|
||||
if ( $( '#recursively' ).is( ':checked' ) ) {
|
||||
$( '#recursive-details, .recursive-detail' ).show();
|
||||
@@ -277,6 +548,123 @@ echo $grid -> draw();
|
||||
}
|
||||
}
|
||||
|
||||
function refreshAttachmentsState() {
|
||||
var task_id = parseInt( $( '#id' ).val(), 10 ) || 0;
|
||||
var attachments_box = $( '.task-edit-attachments' );
|
||||
|
||||
if ( !attachments_box.length )
|
||||
return;
|
||||
|
||||
attachments_box.attr( 'data-task-id', task_id );
|
||||
task_edit_root.attr( 'data-task-id', task_id );
|
||||
|
||||
if ( task_id > 0 ) {
|
||||
attachments_box.find( '.attachments-requires-save' ).hide();
|
||||
attachments_box.find( '.attachments-ready' ).show();
|
||||
attachments_box.find( '.attachment-upload-btn' ).attr( 'task_id', task_id );
|
||||
} else {
|
||||
attachments_box.find( '.attachments-requires-save' ).show();
|
||||
attachments_box.find( '.attachments-ready' ).hide();
|
||||
}
|
||||
}
|
||||
|
||||
function escapeHtml( text ) {
|
||||
return String( text )
|
||||
.replace( /&/g, '&' )
|
||||
.replace( /</g, '<' )
|
||||
.replace( />/g, '>' )
|
||||
.replace( /"/g, '"' )
|
||||
.replace( /'/g, ''' );
|
||||
}
|
||||
|
||||
function setAttachmentsTabCount( count ) {
|
||||
task_edit_root.find( '.js-attachments-tab-btn' ).text( 'Załączniki (' + count + ')' );
|
||||
}
|
||||
|
||||
function renderAttachmentsList( attachments ) {
|
||||
var attachments_box = $( '.task-edit-attachments' );
|
||||
var list = attachments_box.find( '.attachments_list' );
|
||||
var html = '';
|
||||
|
||||
if ( attachments && attachments.length )
|
||||
{
|
||||
for ( var i = 0; i < attachments.length; i++ )
|
||||
{
|
||||
var item = attachments[i];
|
||||
var title = item.title_effective ? item.title_effective : '';
|
||||
var size_human = item.size_human ? item.size_human : '';
|
||||
var url = item.url ? item.url : '#';
|
||||
var attachment_id = item.id ? item.id : '';
|
||||
|
||||
html += ''
|
||||
+ '<li class="attachment-item">'
|
||||
+ '<a href="' + escapeHtml( url ) + '" target="_blank" rel="noopener noreferrer" class="attachment-link" download="' + escapeHtml( title ) + '">' + escapeHtml( title ) + '</a> '
|
||||
+ '<small>(' + escapeHtml( size_human ) + ')</small> '
|
||||
+ '<a href="#" class="attachment-rename" attachment_id="' + escapeHtml( attachment_id ) + '" title_current="' + escapeHtml( title ) + '"><i class="fa fa-pencil"></i></a> '
|
||||
+ '<a href="#" class="attachment-delete" attachment_id="' + escapeHtml( attachment_id ) + '"><i class="fa fa-trash"></i></a>'
|
||||
+ '</li>';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
html = '<li class="attachments-empty">Brak załączników.</li>';
|
||||
}
|
||||
|
||||
list.html( html );
|
||||
setAttachmentsTabCount( attachments ? attachments.length : 0 );
|
||||
}
|
||||
|
||||
function refreshAttachmentsList( task_id, callback, options ) {
|
||||
options = options || {};
|
||||
var should_activate_tab = options.activate_tab === false ? false : true;
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
cache: false,
|
||||
url: '/tasks/task_attachments_list/',
|
||||
data: {
|
||||
task_id: task_id
|
||||
},
|
||||
success: function( response ) {
|
||||
var data = ( typeof response === 'string' ) ? jQuery.parseJSON( response ) : response;
|
||||
if ( data.status === 'success' )
|
||||
{
|
||||
renderAttachmentsList( data.attachments );
|
||||
if ( should_activate_tab )
|
||||
setActiveTaskEditTab( 'attachments' );
|
||||
if ( typeof callback === 'function' )
|
||||
callback( true, data );
|
||||
}
|
||||
else
|
||||
{
|
||||
$.alert( data.msg ? data.msg : 'Nie udało się odświeżyć listy załączników.' );
|
||||
if ( typeof callback === 'function' )
|
||||
callback( false, data );
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
$.alert( 'Nie udało się odświeżyć listy załączników.' );
|
||||
if ( typeof callback === 'function' )
|
||||
callback( false, null );
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function waitForTaskIdAfterSave( attempt ) {
|
||||
var task_id = parseInt( $( '#id' ).val(), 10 ) || 0;
|
||||
if ( task_id > 0 ) {
|
||||
refreshAttachmentsState();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( attempt < 10 )
|
||||
{
|
||||
setTimeout( function() {
|
||||
waitForTaskIdAfterSave( attempt + 1 );
|
||||
}, 350 );
|
||||
}
|
||||
}
|
||||
|
||||
$('input[type="checkbox"]').iCheck({
|
||||
checkboxClass: 'icheckbox_square-blue',
|
||||
radioClass: 'iradio_square-blue',
|
||||
@@ -288,6 +676,190 @@ echo $grid -> draw();
|
||||
toggleRecursiveDetails();
|
||||
});
|
||||
|
||||
refreshAttachmentsState();
|
||||
var initial_task_id = parseInt( $( '#id' ).val(), 10 ) || 0;
|
||||
if ( initial_task_id > 0 )
|
||||
refreshAttachmentsList( initial_task_id, null, { activate_tab: false } );
|
||||
|
||||
$( 'body' ).on( 'click', '#g-edit-save[persist_edit="1"]', function() {
|
||||
setTimeout( function() {
|
||||
waitForTaskIdAfterSave( 0 );
|
||||
}, 350 );
|
||||
});
|
||||
|
||||
$( 'body' ).on( 'click', '.task-edit-attachments .attachment-upload-btn', function( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
var button = $( this );
|
||||
if ( button.hasClass( 'is-loading' ) )
|
||||
return;
|
||||
|
||||
var task_id = parseInt( $( '#id' ).val(), 10 ) || 0;
|
||||
var input = button.closest( '.attachments_upload' ).find( '.attachment_file_input' );
|
||||
var files = input.get( 0 ).files;
|
||||
var original_button_html = button.html();
|
||||
|
||||
if ( !task_id ) {
|
||||
$.alert( 'Najpierw zapisz zadanie.' );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !files || !files.length ) {
|
||||
$.alert( 'Najpierw wybierz pliki.' );
|
||||
return;
|
||||
}
|
||||
|
||||
button
|
||||
.addClass( 'is-loading disabled' )
|
||||
.attr( 'aria-disabled', 'true' )
|
||||
.html( '<i class="fa fa-spinner fa-spin"></i> Wysyłanie...' );
|
||||
input.prop( 'disabled', true );
|
||||
|
||||
var formData = new FormData();
|
||||
formData.append( 'task_id', task_id );
|
||||
for ( var i = 0; i < files.length; i++ )
|
||||
formData.append( 'attachments[]', files[i] );
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
cache: false,
|
||||
url: '/tasks/task_attachment_upload/',
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success: function( response ) {
|
||||
var data = jQuery.parseJSON( response );
|
||||
if ( data.status == 'success' || data.status == 'partial' ) {
|
||||
if ( data.status == 'partial' && data.msg )
|
||||
$.alert( data.msg );
|
||||
|
||||
refreshAttachmentsList( task_id, function() {
|
||||
input.val( '' );
|
||||
} );
|
||||
} else {
|
||||
$.alert( data.msg ? data.msg : 'Nie udało się dodać załączników.' );
|
||||
}
|
||||
},
|
||||
complete: function() {
|
||||
button
|
||||
.removeClass( 'is-loading disabled' )
|
||||
.removeAttr( 'aria-disabled' )
|
||||
.html( original_button_html );
|
||||
input.prop( 'disabled', false );
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$( 'body' ).on( 'click', '.task-edit-attachments .attachment-delete', function( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
var attachment_id = $( this ).attr( 'attachment_id' );
|
||||
var task_id = parseInt( $( '#id' ).val(), 10 ) || 0;
|
||||
if ( !task_id ) {
|
||||
$.alert( 'Najpierw zapisz zadanie.' );
|
||||
return;
|
||||
}
|
||||
|
||||
$.confirm({
|
||||
title: 'Potwierdź',
|
||||
content: 'Na pewno chcesz usunąć załącznik?',
|
||||
type: 'orange',
|
||||
closeIcon: true,
|
||||
closeIconClass: 'fa fa-close',
|
||||
typeAnimated: true,
|
||||
animation: 'opacity',
|
||||
boxWidth: '500px',
|
||||
useBootstrap: false,
|
||||
theme: 'material',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: 'Usuń',
|
||||
btnClass: 'btn-red',
|
||||
action: function() {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
cache: false,
|
||||
url: '/tasks/task_attachment_delete/',
|
||||
data: {
|
||||
attachment_id: attachment_id
|
||||
},
|
||||
success: function( response ) {
|
||||
var data = jQuery.parseJSON( response );
|
||||
if ( data.status == 'success' )
|
||||
refreshAttachmentsList( task_id );
|
||||
else
|
||||
$.alert( 'Nie udało się usunąć załącznika.' );
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
cancel: {
|
||||
text: 'Anuluj',
|
||||
btnClass: 'btn-default',
|
||||
action: function() {}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$( 'body' ).on( 'click', '.task-edit-attachments .attachment-rename', function( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
var attachment_id = $( this ).attr( 'attachment_id' );
|
||||
var current_title = $( this ).attr( 'title_current' );
|
||||
var task_id = parseInt( $( '#id' ).val(), 10 ) || 0;
|
||||
if ( !task_id ) {
|
||||
$.alert( 'Najpierw zapisz zadanie.' );
|
||||
return;
|
||||
}
|
||||
|
||||
$.confirm({
|
||||
title: 'Zmień nazwę załącznika',
|
||||
content: ''
|
||||
+ '<form action="" class="formName">'
|
||||
+ '<div class="form-group">'
|
||||
+ '<input type="text" class="attachment-new-title form-control" value="' + $('<div>').text(current_title).html() + '" />'
|
||||
+ '</div>'
|
||||
+ '</form>',
|
||||
buttons: {
|
||||
formSubmit: {
|
||||
text: 'Zapisz',
|
||||
btnClass: 'btn-blue',
|
||||
action: function () {
|
||||
var new_title = this.$content.find( '.attachment-new-title' ).val();
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
cache: false,
|
||||
url: '/tasks/task_attachment_rename/',
|
||||
data: {
|
||||
attachment_id: attachment_id,
|
||||
title: new_title
|
||||
},
|
||||
success: function( response ) {
|
||||
var data = jQuery.parseJSON( response );
|
||||
if ( data.status == 'success' )
|
||||
refreshAttachmentsList( task_id );
|
||||
else
|
||||
$.alert( 'Nie udało się zmienić nazwy załącznika.' );
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
cancel: {
|
||||
text: 'Anuluj',
|
||||
action: function () {}
|
||||
}
|
||||
},
|
||||
onContentReady: function () {
|
||||
var jc = this;
|
||||
this.$content.find( 'form' ).on( 'submit', function (e) {
|
||||
e.preventDefault();
|
||||
jc.$$formSubmit.trigger( 'click' );
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$( 'body' ).on( 'click', '.task-remove', function(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
@@ -343,12 +915,12 @@ echo $grid -> draw();
|
||||
height: '100'
|
||||
});
|
||||
|
||||
$( '#project_id, #client_id, #status' ).select2({
|
||||
$( '#project_id, #client_id, #status, #parent_id, #priority' ).select2({
|
||||
theme: 'bootstrap-5',
|
||||
minimumResultsForSearch: 0
|
||||
});
|
||||
|
||||
$( '#project_id, #client_id, #status' ).on( 'select2:open', function() {
|
||||
$( '#project_id, #client_id, #status, #parent_id, #priority' ).on( 'select2:open', function() {
|
||||
setTimeout( function() {
|
||||
var search_field = document.querySelector( '.select2-container--open .select2-search__field' );
|
||||
if ( search_field )
|
||||
@@ -358,5 +930,54 @@ echo $grid -> draw();
|
||||
}
|
||||
}, 0 );
|
||||
});
|
||||
|
||||
// Override globalne funkcje komunikatów dla tej strony
|
||||
window.create_message_original = window.create_message;
|
||||
window.create_error_original = window.create_error;
|
||||
|
||||
function showTaskEditMessage( msg, type ) {
|
||||
var messageClass = type === 'success' ? 'alert-success' : 'alert-danger';
|
||||
var icon = type === 'success' ? '<i class="fa fa-check-circle"></i>' : '<i class="fa fa-exclamation-circle"></i>';
|
||||
var containerId = 'task-edit-message-container';
|
||||
|
||||
// Usuń stary komunikat jeśli istnieje
|
||||
$( '#' + containerId ).remove();
|
||||
|
||||
// Dodaj DIV dla komunikatów na górze formularza
|
||||
task_edit_root.before( '<div id="' + containerId + '" class="task-edit-message alert ' + messageClass + '" role="alert">' +
|
||||
icon +
|
||||
'<span style="margin-left: 8px;">' + msg + '</span>' +
|
||||
'<button type="button" class="task-edit-message-close" aria-label="Zamknij" style="position: absolute; right: 12px; top: 50%; transform: translateY(-50%); background: none; border: none; font-size: 20px; cursor: pointer; color: inherit;">×</button>' +
|
||||
'</div>' );
|
||||
|
||||
// Handler dla przycisku zamknięcia
|
||||
$( '#' + containerId ).find( '.task-edit-message-close' ).on( 'click', function() {
|
||||
$( '#' + containerId ).fadeOut( 300, function() {
|
||||
$( this ).remove();
|
||||
});
|
||||
});
|
||||
|
||||
// Automatycznie ukryj komunikat po 5 sekundach jeśli to sukces
|
||||
if ( type === 'success' ) {
|
||||
setTimeout( function() {
|
||||
var msg = $( '#' + containerId );
|
||||
if ( msg.length ) {
|
||||
msg.fadeOut( 300, function() {
|
||||
$( this ).remove();
|
||||
});
|
||||
}
|
||||
}, 5000 );
|
||||
}
|
||||
}
|
||||
|
||||
// Przechwytuj wywołania funkcji create_message
|
||||
window.create_message = function( text ) {
|
||||
showTaskEditMessage( text, 'success' );
|
||||
};
|
||||
|
||||
// Przechwytuj wywołania funkcji create_error
|
||||
window.create_error = function( text ) {
|
||||
showTaskEditMessage( text, 'error' );
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user