diff --git a/.claude/memory/MEMORY.md b/.claude/memory/MEMORY.md
new file mode 100644
index 0000000..5437754
--- /dev/null
+++ b/.claude/memory/MEMORY.md
@@ -0,0 +1,3 @@
+# Memory Index
+
+- [feedback_polish.md](feedback_polish.md) — Komunikacja po polsku
diff --git a/.claude/memory/feedback_polish.md b/.claude/memory/feedback_polish.md
new file mode 100644
index 0000000..1fd8b8d
--- /dev/null
+++ b/.claude/memory/feedback_polish.md
@@ -0,0 +1,10 @@
+---
+name: Komunikacja po polsku
+description: Użytkownik chce, żeby Claude pisał do niego po polsku
+type: feedback
+---
+
+Zawsze komunikuj się z użytkownikiem po polsku.
+
+**Why:** Użytkownik wyraźnie poprosił o komunikację w języku polskim.
+**How to apply:** Wszystkie odpowiedzi, pytania i podsumowania pisz po polsku.
diff --git a/autoload/controls/class.Tasks.php b/autoload/controls/class.Tasks.php
index 417fa8f..4afeb52 100644
--- a/autoload/controls/class.Tasks.php
+++ b/autoload/controls/class.Tasks.php
@@ -593,6 +593,29 @@ class Tasks
exit;
}
+ static public function task_work_logs_popup()
+ {
+ global $user;
+
+ if ( !$user )
+ {
+ header( 'Location: /logowanie' );
+ exit;
+ }
+
+ $task_id = (int)\S::get( 'task_id' );
+ $task = \factory\Tasks::task_details( $task_id, $user['id'] );
+
+ if ( !is_array( $task ) )
+ $task = [ 'id' => $task_id, 'name' => '' ];
+
+ echo \Tpl::view( 'tasks/task_work_logs_popup', [
+ 'task' => $task,
+ 'task_works' => \factory\Tasks::task_works( $task_id )
+ ] );
+ exit;
+ }
+
static public function task_attachment_upload()
{
global $user;
diff --git a/templates/tasks/task_work_logs_popup.php b/templates/tasks/task_work_logs_popup.php
new file mode 100644
index 0000000..aeec490
--- /dev/null
+++ b/templates/tasks/task_work_logs_popup.php
@@ -0,0 +1,81 @@
+
+$to_input_datetime = function( $datetime ) {
+ if ( !$datetime )
+ return '';
+
+ $timestamp = strtotime( (string)$datetime );
+ if ( $timestamp === false )
+ return '';
+
+ return date( 'Y-m-d\TH:i', $timestamp );
+};
+
+$resolve_user_name = function( $user_id ) {
+ static $cache = [];
+ $user_id = (int)$user_id;
+
+ if ( !isset( $cache[ $user_id ] ) )
+ {
+ $details = \factory\Users::user_details( $user_id );
+ $name = 'Nieznany użytkownik';
+
+ if ( is_array( $details ) )
+ {
+ $full_name = trim( trim( (string)( $details['name'] ?? '' ) ) . ' ' . trim( (string)( $details['surname'] ?? '' ) ) );
+ if ( $full_name !== '' )
+ $name = $full_name;
+ }
+
+ $cache[ $user_id ] = $name;
+ }
+
+ return $cache[ $user_id ];
+};
+?>
+
diff --git a/templates/tasks/work-time.php b/templates/tasks/work-time.php
index 9ca8077..348762b 100644
--- a/templates/tasks/work-time.php
+++ b/templates/tasks/work-time.php
@@ -157,7 +157,11 @@ usort( $billing_clients, function( $a, $b ) {
| = $row['month'];?> |
= $row['name'];?> |
- = $format_time( $row['time'] );?> |
+
+
+ |
= $format_amount( $row['amount'] );?> |
zamknij zadanie
@@ -250,6 +254,54 @@ usort( $billing_clients, function( $a, $b ) {
onConfirm();
}
+ function showPopupMessage( message ) {
+ if ( typeof $.alert === 'function' )
+ {
+ $.alert({
+ title: 'Informacja',
+ content: message
+ });
+ return;
+ }
+
+ alert( message );
+ }
+
+ function openWorkLogsPopup( task_id, task_name ) {
+ $.ajax({
+ type: 'POST',
+ cache: false,
+ url: '/tasks/task_work_logs_popup/',
+ data: {
+ task_id: task_id
+ },
+ success: function( response ) {
+ if ( typeof $.confirm !== 'function' )
+ {
+ showPopupMessage( 'Brak obsługi popupu w tej konfiguracji.' );
+ return;
+ }
+
+ $.confirm({
+ title: 'Time tracking: ' + task_name,
+ content: response,
+ type: 'blue',
+ boxWidth: '980px',
+ useBootstrap: false,
+ backgroundDismiss: true,
+ buttons: {
+ close: {
+ text: 'Zamknij'
+ }
+ }
+ });
+ },
+ error: function() {
+ showPopupMessage( 'Nie udało się pobrać wpisów time trackingu.' );
+ }
+ });
+ }
+
$( 'body' ).on( 'click', '.toggle-billing-details', function(e){
e.preventDefault();
@@ -279,6 +331,70 @@ usort( $billing_clients, function( $a, $b ) {
});
});
+ $( 'body' ).on( 'click', '.open-work-logs-popup', function(e){
+ e.preventDefault();
+ var task_id = parseInt( $( this ).attr( 'task-id' ), 10 ) || 0;
+ var task_name = $( this ).attr( 'task-name' ) || ( 'Zadanie #' + task_id );
+
+ if ( !task_id )
+ {
+ showPopupMessage( 'Brak identyfikatora zadania.' );
+ return;
+ }
+
+ openWorkLogsPopup( task_id, task_name );
+ });
+
+ $( 'body' ).on( 'click', '.js-save-work-log', function(e){
+ e.preventDefault();
+
+ var button = $( this );
+ var row = button.closest( '.js-work-log-row' );
+ var task_work_id = parseInt( button.attr( 'task_work_id' ), 10 ) || 0;
+ var date_start = row.find( '.js-work-log-start' ).val();
+ var date_end = row.find( '.js-work-log-end' ).val();
+
+ if ( !task_work_id )
+ {
+ showPopupMessage( 'Brak identyfikatora wpisu.' );
+ return;
+ }
+
+ if ( !date_start || !date_end )
+ {
+ showPopupMessage( 'Uzupełnij datę start i koniec.' );
+ return;
+ }
+
+ button.attr( 'disabled', 'disabled' );
+
+ $.when(
+ $.ajax({
+ type: 'POST',
+ cache: false,
+ url: '/tasks/change_task_work_date_start/',
+ data: {
+ task_work_id: task_work_id,
+ date_start: date_start
+ }
+ }),
+ $.ajax({
+ type: 'POST',
+ cache: false,
+ url: '/tasks/change_task_work_date_end/',
+ data: {
+ task_work_id: task_work_id,
+ date_end: date_end
+ }
+ })
+ ).done( function() {
+ window.location.reload();
+ }).fail( function() {
+ button.removeAttr( 'disabled' );
+ showPopupMessage( 'Nie udało się zapisać zmian wpisu.' );
+ });
+ });
+
$( 'body' ).on( 'click', '.close-task', function(e){
e.preventDefault();
diff --git a/templates/wiki/main-view.php b/templates/wiki/main-view.php
index 6a2193f..aa45b00 100644
--- a/templates/wiki/main-view.php
+++ b/templates/wiki/main-view.php
@@ -35,9 +35,6 @@
if ( is_array( $this -> categories ) and count( $this -> categories ) ):?>
foreach ( $this -> categories as $category ):?>
$category_name = isset( $category['name'] ) ? (string)$category['name'] : '';?>
- $category_text = isset( $category['text'] ) ? strip_tags( (string)$category['text'] ) : '';?>
- $category_preview = trim( $category_text );?>
- if ( strlen( $category_preview ) > 170 ) $category_preview = substr( $category_preview, 0, 170 ) . '...';?>
- if ( $category_preview !== '' ):?>
- = htmlspecialchars( $category_preview );?>
- else:?>
- Brak podglądu treści.
- endif;?>
$category_users = \factory\Wiki::category_users( (int)$category['id'] );?>
@@ -77,18 +69,10 @@
if ( is_array( $this -> categories ) and count( $this -> categories ) ):?>
foreach ( $this -> categories as $category ):?>
$category_name = isset( $category['name'] ) ? (string)$category['name'] : '';?>
- $category_text = isset( $category['text'] ) ? strip_tags( (string)$category['text'] ) : '';?>
- $category_preview = trim( $category_text );?>
- if ( strlen( $category_preview ) > 170 ) $category_preview = substr( $category_preview, 0, 170 ) . '...';?>
- if ( $category_preview !== '' ):?>
- = htmlspecialchars( $category_preview );?>
- else:?>
- Brak podglądu treści.
- endif;?>
endforeach;?>
else:?>
@@ -154,21 +138,22 @@
.wiki-main .wiki-categories-grid {
display: grid;
- gap: 12px;
- grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
+ gap: 14px;
+ grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
}
.wiki-main .wiki-card {
display: flex;
flex-direction: column;
- gap: 10px;
+ gap: 12px;
border: 1px solid var(--wiki-border);
border-radius: 10px;
- padding: 12px;
+ padding: 14px;
background: #fff;
transition: border-color .2s ease, box-shadow .2s ease, transform .2s ease;
min-width: 0;
overflow: hidden;
+ min-height: 96px;
}
.wiki-main .wiki-card:hover {
@@ -197,20 +182,6 @@
text-decoration: underline;
}
- .wiki-main .wiki-card-preview {
- color: var(--wiki-text);
- font-size: 13px;
- line-height: 1.45;
- min-height: 38px;
- overflow-wrap: anywhere;
- word-break: break-word;
- }
-
- .wiki-main .wiki-card-preview-empty {
- color: var(--wiki-muted);
- font-style: italic;
- }
-
.wiki-main .wiki-card-bottom {
display: flex;
align-items: center;
@@ -271,6 +242,12 @@
max-width: none;
}
}
+
+ @media (min-width: 1400px) {
+ .wiki-main .wiki-categories-grid {
+ grid-template-columns: repeat(auto-fill, minmax(380px, 1fr));
+ }
+ }
|