Files
crmPRO/templates/tasks/task_popup.php

548 lines
22 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<div class="task_details" task_id="<?= $this -> task['id'];?>">
<a href="#" class="close"><i class="fa fa-times"></i></a>
<div class="title">
<a href="/tasks/task_edit/task_id=<?= $this -> task['id'];?>" class="_edit">
<i class="fa fa-pencil"></i>
</a>
<? if ( $this -> user['id'] == 1 ):?>
<a href="#" class="task-delete" task_id="<?= $this -> task['id'];?>">
<i class="fa fa-trash"></i>
</a>
<? endif;?>
#<?= $this -> task['id'];?> <?= $this -> task['name'];?>
</div>
<?
$checklist_count = is_array( $this -> task['actions'] ) ? count( $this -> task['actions'] ) : 0;
$comments_count = is_array( $this -> task['comments'] ) ? count( $this -> task['comments'] ) : 0;
$attachments_count = is_array( $this -> task_attachments ) ? count( $this -> task_attachments ) : 0;
?>
<div class="content">
<div class="left">
<div class="task-tabs-nav" role="tablist" aria-label="Prze&#322;&#261;cz zak&#322;adk&#281; zadania">
<a href="#" class="js-task-tab-btn is-active" data-tab="description" role="tab" aria-selected="true">Opis</a>
<a href="#" class="js-task-tab-btn" data-tab="checklist" role="tab" aria-selected="false">Lista kontrolna (<?= (int)$checklist_count;?>)</a>
<a href="#" class="js-task-tab-btn" data-tab="comments" role="tab" aria-selected="false">Komentarze (<?= (int)$comments_count;?>)</a>
<a href="#" class="js-task-tab-btn" data-tab="attachments" role="tab" aria-selected="false">Za&#322;&#261;czniki (<?= (int)$attachments_count;?>)</a>
<? if ( $this -> user['id'] == 1 ):?>
<a href="#" class="js-task-tab-btn" data-tab="users" role="tab" aria-selected="false">Uczestnicy</a>
<? endif;?>
</div>
<div class="users box">
<? if ( is_array( $this -> task['users'] ) ): foreach ( $this -> task['users'] as $user_tmp_id ):?>
<? $user_tmp = \factory\Users::user_details( $user_tmp_id );?>
<div class="user">
<div class="avatar" style="background: <?= $user_tmp['color'];?>;" title="<?= $user_tmp['name'] . $user_tmp['surname'];?>"><?= $user_tmp['name'][0] . $user_tmp['surname'][0];?></div>
<?= $user_tmp['name'] . $user_tmp['surname'];?>
</div>
<? endforeach; endif;?>
</div>
<div class="task-tab-panel is-active" data-tab="description">
<? if ( $this -> task['text'] ):?>
<div class="description">
<a href="#" class="fullscreen"><i class="fa fa-expand"></i></a>
<?= htmlspecialchars_decode( $this -> task['text'] );?>
</div>
<? else:?>
<div class="description description-empty">
Brak opisu zadania.
</div>
<? endif;?>
</div>
<div class="task-tab-panel" data-tab="checklist">
<div class="checklist">
<h3>Lista kontrolna</h3>
<div class="new_element">
<input type="text" class="form-control" placeholder="Dodaj nowy element">
<a href="#" class="add_element" task_id="<?= $this -> task['id'];?>"><i class="fa fa-plus"></i></a>
</div>
<ul>
<? foreach ( $this -> task['actions'] as $action ):?>
<li action_id="<?= $action['id'];?>">
<input type="checkbox" class="g-checkbox" value="<?= $action[ 'id' ];?>" <? if ( $action['status'] ):?>checked="checked"<? endif;?>>
<?= $action['name'];?>
<a href="#" class="point-delete" action_id="<?= $action['id'];?>">
<i class="fa fa-trash"></i>
</a>
</li>
<? endforeach;?>
</ul>
</div>
</div>
<div class="task-tab-panel" data-tab="comments">
<div class="comments">
<h3>Komentarze</h3>
<div class="new_comment">
<textarea class="form-control" placeholder="Dodaj nowy komentarz"></textarea>
<a href="#" class="add_comment" task_id="<?= $this -> task['id'];?>">Dodaj nowy komentarz</a>
</div>
<ul>
<? foreach ( $this -> task['comments'] as $comment ):?>
<li>
<a href="#" class="delete_comment" comment_id="<?= $comment['id'];?>"><i class="fa fa-trash"></i></a>
<div class="author"><?= \factory\Users::user_details( $comment['user_id'] )['name'] . ' ' . \factory\Users::user_details( $comment['user_id'] )['surname'];?></div>
<div class="date"><?= date( 'Y/m/d H:i', strtotime( $comment['date_add'] ) );?></div>
<div class="text"><?= nl2br( $comment['text'] );?></div>
</li>
<? endforeach;?>
</ul>
</div>
</div>
<div class="task-tab-panel" data-tab="attachments">
<div class="attachments box">
<h3>Za&#322;&#261;czniki</h3>
<div class="attachments_upload">
<input type="file" class="form-control attachment_file_input" name="attachments[]" multiple>
<a href="#" class="attachment-upload-btn btn btn-primary btn-sm" task_id="<?= $this -> task['id'];?>">Dodaj za&#322;&#261;czniki</a>
</div>
<ul class="attachments_list">
<? if ( is_array( $this -> task_attachments ) and count( $this -> task_attachments ) ):?>
<? foreach ( $this -> task_attachments as $attachment ):?>
<li>
<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&#322;&#261;cznik&#243;w.</li>
<? endif;?>
</ul>
</div>
</div>
<? if ( $this -> user['id'] == 1 ):?>
<div class="task-tab-panel" data-tab="users">
<div class="task-users-edit">
<h3>Uczestnicy</h3>
<div class="task-users-checkboxes">
<? if ( is_array( $this -> all_users ) ): foreach ( $this -> all_users as $u ):?>
<label class="task-user-label">
<input type="checkbox" class="task-user-checkbox g-checkbox" value="<?= $u['id'];?>" <? if ( is_array( $this -> task['users'] ) and in_array( $u['id'], $this -> task['users'] ) ):?>checked="checked"<? endif;?>>
<?= $u['name'] . ' ' . $u['surname'];?>
</label>
<? endforeach; endif;?>
</div>
<div class="task-users-options">
<label class="task-user-label task-status-mail-label">
<input type="checkbox" class="task-status-change-mail-checkbox g-checkbox" value="1" <? if ( (int)$this -> task['status_change_mail'] === 1 ):?>checked="checked"<? endif;?>>
Powiadom o zmianie statusu:
</label>
</div>
<a href="#" class="btn btn-primary btn-sm js-save-task-users" task_id="<?= $this -> task['id'];?>" style="margin-top: 10px;">Zapisz</a>
</div>
</div>
<? endif;?>
</div>
<div class="right">
<div class="status box">
<h3>Status</h3>
<div class="current_status">
<select name="task_status" class="form-control" task_id="<?= $this -> task['id'];?>">
<? foreach ( \factory\Tasks::get_statuses() as $key => $status ):?>
<option value="<?= $key;?>" <? if ( $this -> task['status'] == $key ):?>selected="selected"<? endif;?>><?= $status;?></option>
<? endforeach;?>
</select>
</div>
</div>
<div class="priority box">
<h3>Priorytet</h3>
<div class="current_priority">
<select name="task_priority" class="form-control" task_id="<?= $this -> task['id'];?>">
<? foreach ( \factory\Tasks::get_priorities() as $key => $priority ):?>
<option value="<?= $key;?>" <? if ( $this -> task['priority'] == $key ):?>selected="selected"<? endif;?>><?= $priority;?></option>
<? endforeach;?>
</select>
</div>
</div>
<div class="project box">
<h3>Projekt</h3>
<div class="current_project">
<select name="task_project" class="form-control" task_id="<?= $this -> task['id'];?>">
<option value="0">-- brak --</option>
<? foreach ( $this -> projects as $project ):?>
<option value="<?= $project['id'];?>" <? if ( $this -> task['project_id'] == $project['id'] ):?>selected="selected"<? endif;?>><?= $project['name'];?></option>
<? endforeach;?>
</select>
</div>
</div>
<div class="dates box">
<h3>Termin</h3>
<? if ( $this -> task['date_start'] ):?>
<div class="date_start"><i class="fa fa-regular fa-calendar"></i><?= $this -> task['date_start'];?></div>
<? endif;?>
<? if ( $this -> task['date_end'] ):?>
<div class="date_end <? if ( $this -> task['status'] != 2 and $this -> task['date_end'] == date( 'Y-m-d' ) ):?> warning<? endif;?> <? if ( $this -> task['status'] != 2 and $this -> task['date_end'] < date( 'Y-m-d' ) ):?> dangerx<? endif;?>"><i class="fa fa-regular fa-calendar"></i><?= $this -> task['date_end'];?></div>
<? endif;?>
</div>
<div class="client box">
<h3>Klient</h3>
<div class="current_client">
<select name="task_client" class="form-control task_client_select" task_id="<?= $this -> task['id'];?>">
<option value="0">-- brak --</option>
<? if ( is_array( $this -> clients ) ): foreach ( $this -> clients as $client ):?>
<option value="<?= (int)$client['id'];?>" <? if ( (int)$this -> task['client_id'] === (int)$client['id'] ):?>selected="selected"<? endif;?>>
<?= htmlspecialchars( $client['firm'] );?>
</option>
<? endforeach; endif;?>
</select>
</div>
</div>
<div class="time box">
<h3>Przepracowany czas</h3>
<div class="time_worked" data-total-seconds="<?= (int)$this -> task['total_time'];?>">
<a href="#" class="time_worked_toggle js-time-worked-value">
<?= sprintf( "%02d%s%02d%s%02d", floor( $this -> task['total_time'] / 3600 ), ':', ( $this -> task['total_time'] / 60) % 60, ':', $this -> task['total_time'] % 60 );?>
</a>
</div>
<a href="#" class="task_start <? if ( $this -> task['is_open'] ):?> hidden<? endif;?>" task_id="<?= $this -> task['id'];?>">
<i class="fa fa-play"></i> W&#322;&#261;cz timer
</a>
<a href="#" class="task_end <? if ( !$this -> task['is_open'] ):?> hidden<? else:?> animate<? endif;?>" task_id="<?= $this -> task['id'];?>">
<i class="fa fa-stop"></i> Wy&#322;&#261;cz timer
</a>
</div>
</div>
<div class="task_work_details">
<? foreach ( $this -> task_works as $task_work ):?>
<div class="_line">
<div class="_user"><?= \factory\Users::user_details( $task_work['user_id'] )['name'] . ' ' . \factory\Users::user_details( $task_work['user_id'] )['surname'];?></div>
<input type="text" class="form-control task_work_date_start" task_work_id="<?= $task_work['id'];?>" value="<?= $task_work['date_start'];?>"><span>-</span><input type="text" class="form-control task_work_date_end" task_work_id="<?= $task_work['id'];?>" value="<?= $task_work['date_end'];?>">
<a href="#" class="_work_delete" work_id="<?= $task_work['id'];?>" task_id="<?= $this -> task['id'];?>">
<i class="fa fa-trash"></i>
</a>
</div>
<? endforeach;?>
</div>
</div>
</div>
<style type="text/css">
.task_popup .task_details .content .right .client .select2-container {
width: 100% !important;
}
.task_popup .task_details .content .left .task-tabs-nav {
margin: 0 0 10px 0;
display: flex;
flex-wrap: wrap;
border: 1px solid #d8e2f6;
border-radius: 8px;
overflow: hidden;
background: #f4f8ff;
position: sticky;
top: 0;
z-index: 30;
}
.task_popup .task_details .content .left .task-tabs-nav .js-task-tab-btn {
padding: 8px 12px;
color: #355899;
text-decoration: none;
font-size: 13px;
font-weight: 600;
border-right: 1px solid #d8e2f6;
transition: all 0.2s ease;
}
.task_popup .task_details .content .left .task-tabs-nav .js-task-tab-btn:last-child {
border-right: 0;
}
.task_popup .task_details .content .left .task-tabs-nav .js-task-tab-btn:hover {
background: #e7f0ff;
}
.task_popup .task_details .content .left .task-tabs-nav .js-task-tab-btn.is-active {
background: #6690f4;
color: #fff;
}
.task_popup .task_details .content .left .task-tab-panel {
margin-top: 10px;
display: none;
}
.task_popup .task_details .content .left .task-tab-panel.is-active {
display: block;
}
.task_popup .task_details .content .left .task-tab-panel .attachments {
margin-top: 0;
}
.task_popup .task_details .content .left .task-tab-panel .description.description-empty {
color: #6b7280;
font-style: italic;
}
.task_popup .task_details .content .left .task-tab-panel[data-tab="description"] .description:not(.description-empty) {
min-height: 320px;
max-height: calc(90vh - 300px);
overflow-y: auto;
}
.task_popup .task_details .content .right .client .select2-container--bootstrap-5 .select2-selection {
min-height: 35px;
border: 1px solid #cdcdcd;
border-radius: 0;
box-shadow: none;
padding: 5px 30px 5px 5px;
display: flex;
align-items: center;
}
.task_popup .task_details .content .right .client .select2-container--bootstrap-5 .select2-selection--single .select2-selection__rendered {
color: #4e5e6a;
padding-left: 0;
padding-right: 0;
line-height: 1.2;
}
.task_popup .task_details .content .right .client .select2-container--bootstrap-5 .select2-selection--single .select2-selection__arrow {
right: 8px;
top: 50%;
transform: translateY(-50%);
}
.task_popup .task_details .content .right .client .select2-container--bootstrap-5.select2-container--focus .select2-selection,
.task_popup .task_details .content .right .client .select2-container--bootstrap-5.select2-container--open .select2-selection {
border-color: #6690f4;
}
.task_popup .task_details .task-users-checkboxes {
display: flex;
flex-direction: column;
gap: 6px;
}
.task_popup .task_details .task-user-label {
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
padding: 4px 0;
font-size: 13px;
}
.task_popup .task_details .task-user-label input[type="checkbox"] {
margin: 0;
}
.task_popup .task_details .task-users-options {
margin-top: 10px;
padding-top: 10px;
border-top: 1px solid #e6e9ed;
}
.task_popup .task_details .task-status-mail-label {
font-weight: 600;
}
/* Lightbox - powiększanie zdjęć w opisie */
.task_popup .task_details .description img {
cursor: zoom-in;
transition: opacity .2s ease;
}
.task_popup .task_details .description img:hover {
opacity: .85;
}
.task-img-lightbox {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 99999;
background: rgba(0,0,0,.85);
display: flex;
align-items: center;
justify-content: center;
cursor: zoom-out;
animation: taskLightboxIn .2s ease;
}
@keyframes taskLightboxIn {
from { opacity: 0; }
to { opacity: 1; }
}
.task-img-lightbox img {
max-width: 90vw;
max-height: 90vh;
border-radius: 4px;
box-shadow: 0 0 40px rgba(0,0,0,.5);
object-fit: contain;
}
.task-img-lightbox .lightbox-close {
position: absolute;
top: 16px;
right: 24px;
color: #fff;
font-size: 32px;
cursor: pointer;
line-height: 1;
text-shadow: 0 0 8px rgba(0,0,0,.6);
}
</style>
<script type="text/javascript">
( function() {
var popup = $( '.task_details[task_id="<?= $this -> task['id'];?>"]' );
if ( !popup.length )
return;
var tab_panels = popup.find( '.task-tab-panel' );
var tab_buttons = popup.find( '.js-task-tab-btn' );
function setActiveTaskTab( tab_name ) {
if ( !tab_panels.length )
return;
var allowed_tabs = [ 'description', 'checklist', 'comments', 'attachments', 'users' ];
var selected_tab = allowed_tabs.indexOf( tab_name ) >= 0 ? tab_name : 'description';
tab_panels.each( function() {
var panel = $( this );
panel.toggleClass( 'is-active', panel.attr( 'data-tab' ) === selected_tab );
});
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_popup_active_tab = selected_tab;
}
popup.on( 'click', '.js-task-tab-btn', function( e ) {
e.preventDefault();
setActiveTaskTab( $( this ).attr( 'data-tab' ) );
} );
setActiveTaskTab( window.crm_task_popup_active_tab || 'description' );
if ( $.fn.select2 )
{
var client_select = popup.find( '.task_client_select' );
client_select.select2({
theme: 'bootstrap-5',
width: '100%',
placeholder: 'Wybierz klienta',
dropdownParent: popup
});
client_select.on( 'select2:open', function() {
setTimeout( function() {
var search_field = document.querySelector( '.select2-container--open .select2-search__field' );
if ( search_field )
search_field.focus();
}, 0 );
} );
}
if ( $.fn.iCheck )
{
popup.find( '.task-user-checkbox, .task-status-change-mail-checkbox' ).iCheck({
checkboxClass: 'icheckbox_square-blue',
radioClass: 'iradio_square-blue'
});
}
var time_worked = popup.find( '.time_worked' );
var time_value = popup.find( '.js-time-worked-value' );
var total_seconds = parseInt( time_worked.attr( 'data-total-seconds' ), 10 ) || 0;
function formatTime( seconds ) {
seconds = parseInt( seconds, 10 ) || 0;
var h = Math.floor( seconds / 3600 );
var m = Math.floor( ( seconds % 3600 ) / 60 );
var s = seconds % 60;
return String( h ).padStart( 2, '0' ) + ':' + String( m ).padStart( 2, '0' ) + ':' + String( s ).padStart( 2, '0' );
}
function renderTime() {
time_value.text( formatTime( total_seconds ) );
time_worked.attr( 'data-total-seconds', total_seconds );
}
renderTime();
// Lightbox kliknięcie na zdjęcie w opisie
popup.on( 'click', '.description img', function( e ) {
e.preventDefault();
e.stopPropagation();
var src = $( this ).attr( 'src' );
if ( !src ) return;
var $overlay = $( '<div class="task-img-lightbox">' +
'<span class="lightbox-close">&times;</span>' +
'<img src="' + src + '">' +
'</div>' );
$( 'body' ).append( $overlay );
$overlay.on( 'click', function() {
$overlay.remove();
});
$( document ).one( 'keydown.taskLightbox', function( ev ) {
if ( ev.key === 'Escape' ) {
$overlay.remove();
}
});
});
popup.on( 'click', '.js-save-task-users', function( e ) {
e.preventDefault();
var btn = $( this );
var task_id = btn.attr( 'task_id' );
var users = [];
var status_change_mail = popup.find( '.task-status-change-mail-checkbox' ).is( ':checked' ) ? 1 : 0;
popup.find( '.task-user-checkbox:checked' ).each( function() {
users.push( $( this ).val() );
});
btn.text( 'Zapisywanie...' ).addClass( 'disabled' );
$.ajax({
type: 'POST',
url: '/tasks/task_change_users/',
data: { task_id: task_id, users: users, status_change_mail: status_change_mail },
success: function( response ) {
var res = typeof response === 'string' ? JSON.parse( response ) : response;
if ( res.status === 'success' ) {
var names = [];
popup.find( '.task-user-checkbox:checked' ).each( function() {
names.push( $( this ).closest( '.task-user-label' ).text().trim() );
});
var html = '';
for ( var i = 0; i < names.length; i++ ) {
var initials = names[i].split( ' ' ).map( function( w ) { return w[0]; } ).join( '' );
html += '<div class="user"><div class="avatar" title="' + names[i] + '">' + initials + '</div>' + names[i] + '</div>';
}
popup.find( '.users.box' ).html( html );
if ( typeof getSelectedTaskFilters === 'function' && typeof reload_tasks === 'function' )
{
var selected_filters = getSelectedTaskFilters();
reload_tasks( selected_filters.projects, selected_filters.users );
}
btn.text( 'Zapisano!' );
} else {
btn.text( 'Błąd' );
}
setTimeout( function() { btn.text( 'Zapisz' ).removeClass( 'disabled' ); }, 1500 );
}
});
});
var interval_id = setInterval( function() {
if ( !document.body.contains( popup.get( 0 ) ) )
{
clearInterval( interval_id );
return;
}
var is_timer_running = !popup.find( '.task_end' ).hasClass( 'hidden' );
if ( is_timer_running )
{
total_seconds++;
renderTime();
}
}, 1000 );
} )();
</script>