%# BEGIN BPS TAGGED BLOCK {{{
%#
%# COPYRIGHT:
%#
%# This software is Copyright (c) 1996-2025 Best Practical Solutions, LLC
%#                                          <sales@bestpractical.com>
%#
%# (Except where explicitly superseded by other copyright notices)
%#
%#
%# LICENSE:
%#
%# This work is made available to you under the terms of Version 2 of
%# the GNU General Public License. A copy of that license should have
%# been provided with this software, but in any event can be snarfed
%# from www.gnu.org.
%#
%# This work is distributed in the hope that it will be useful, but
%# WITHOUT ANY WARRANTY; without even the implied warranty of
%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
%# General Public License for more details.
%#
%# You should have received a copy of the GNU General Public License
%# along with this program; if not, write to the Free Software
%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
%# 02110-1301 or visit their web page on the internet at
%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
%#
%#
%# CONTRIBUTION SUBMISSION POLICY:
%#
%# (The following paragraph is not intended to limit the rights granted
%# to you to modify and distribute this software under the terms of
%# the GNU General Public License and is only of importance to you if
%# you choose to contribute your changes and enhancements to the
%# community by submitting them to Best Practical Solutions, LLC.)
%#
%# By intentionally submitting any modifications, corrections or
%# derivatives to this work, or any other work intended for use with
%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
%# you are the copyright holder for those contributions and you grant
%# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
%# royalty-free, perpetual, license to use, copy, create derivative
%# works based on those contributions, and sublicense and distribute
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
<%ARGS>
$id
</%ARGS>
<%INIT>
my $Ticket = RT::Ticket->new($session{'CurrentUser'});
$Ticket->Load( $id );

my $Now = RT::Date->new($session{'CurrentUser'});
$Now->SetToNow;

my $SubmitURL = RT->Config->Get('WebPath') . '/Helpers/AddTimeWorked';
</%INIT>
<& /Elements/Header, Title => loc('Timer for #[_1]: [_2]', $Ticket->Id, $Ticket->Subject), RichText => 0, ShowBar => 0, ShowTitle => 0, ShowMenu => 0 &>

<script type="text/javascript">
jQuery( function() {
    var Interval;

    // LastUnpause tracks when the current timer started. Then we render
    // (current time - LastUnpause). This is more reliable than a timer
    // that ticks up every second. For example, if JavaScript is temporarily
    // paused (such as being on a background browser tab on a mobile device),
    // the seconds ticker doesn't run. When the timer is paused, LastUnpaused
    // will be a false value.
    var LastUnpause = (new Date).getTime() / 1000;

    // How many seconds has passed since the current timer started?
    var CurrentSeconds = function () {
        if (!LastUnpause) return 0;
        return Math.floor(((new Date).getTime() / 1000) - LastUnpause);
    };

    // CommittedSeconds tracks how long we've "committed" time, which is
    // different from when the timer was initially launched, due to unpausing.
    // Every time we pause, we add (current time - LastUnpause) to
    // CommittedSeconds.
    var CommittedSeconds = 0;

    var Readout = jQuery('.readout');

    var ToHHMMSS = function (Total) {
        var Hours   = Math.floor(Total / 3600);
        var Minutes = Math.floor((Total - (Hours * 3600)) / 60);
        var Seconds = Total - (Hours * 3600) - (Minutes * 60);

        if (Minutes < 10) { Minutes = "0" + Minutes; }
        if (Seconds < 10) { Seconds = "0" + Seconds; }

        return Hours + ':' + Minutes + ':' + Seconds;
    };

    var RenderReadout = function (seconds) {
        Readout.text(ToHHMMSS(seconds));
    };

    var Tick = function () {
        RenderReadout(CommittedSeconds + CurrentSeconds());
    };

    jQuery('.playpause').click(function () {
        if (Interval) {
            // pause
            clearInterval(Interval);
            Interval = false;
            CommittedSeconds += CurrentSeconds();
            LastUnpause = false;
            jQuery('.playpause.play').removeClass('hidden');
            jQuery('.playpause.pause').addClass('hidden');
        }
        else {
            // unpause
            Interval = setInterval(Tick, 1000);
            LastUnpause = new Date().getTime() / 1000;
            jQuery('.playpause.pause').removeClass('hidden');
            jQuery('.playpause.play').addClass('hidden');
        }
        return false;
    });

    jQuery('.submit-time').click(function () {
        clearInterval(Interval);
        jQuery('.control-line a:not(.close-popup)').addClass('hidden');
        CommittedSeconds += CurrentSeconds();

        var Payload = {
            id: <% $Ticket->id %>,
            seconds: CommittedSeconds,
            comment: jQuery('#Comment').val()
        };

        Readout.text('<% loc("Submitting") %>');

        var RenderSubmitError = function (Reason) {
            RenderReadout(CommittedSeconds);
            jQuery('.ticket-timer').addClass('error');

            // give the browser a chance to redraw the readout
            setTimeout(function () {
                alert('<% loc("Unable to submit time. Please add it to the ticket manually. Reason:") %>' + ' ' + Reason);
            }, 100);
        };

        jQuery.ajax({
            url: <% $SubmitURL |n,j %>,
            data: Payload,
            timeout: 30000, /* 30 seconds */
            success: function (Response) {
                if (Response.ok) {
                    Readout.addClass('response');
                    Readout.text(Response.msg);
                    jQuery('.control-line .close-popup').removeClass('hidden');
                }
                else {
                    RenderSubmitError(Response.msg);
                }
            },
            error: function (xhr, reason) {
                RenderSubmitError(reason);
            }
        });

        return false;
    });

    jQuery('.close-popup').click(function () {
        window.close();
        return false;
    });

    Tick();
    Interval = setInterval(Tick, 500);

    // Increase the window size for zoomed in screens, which is common especially on retina displays
    const width = document.querySelector('body').clientWidth;
    if ( width && width < 230  ) {
        const ratio = 230/width;
        window.resizeBy(230*(ratio-1), (document.querySelector('.estimated') ? 300 : 260)*(ratio-1));
    }
});
</script>

<div class="ticket-timer">
    <div class="ticket-link">
        <a target="_blank" href="<%RT->Config->Get('WebPath')%>/Ticket/Display.html?id=<%$Ticket->Id%>">
            <%$Ticket->Id%>: <%$Ticket->Subject%>
        </a>
    </div>

    <div class="gutter">
        <div class="readout"></div>

        <div class="control-line">
            <a href="#" class="playpause pause"><% GetSVGImage( Name => 'pause', Title => loc('Pause Timer') ) |n %></a>
            <a href="#" class="playpause play hidden"><% GetSVGImage( Name => 'play', Title => loc('Resume Timer') ) |n %></a>
            <a href="#" class="submit-time"><% GetSVGImage( Name => 'arrow-up', Title => loc('Submit Timer') ) |n %></a>
            <a href="#" class="close-popup hidden"><% GetSVGImage( Name => 'close-circle', Title => loc('Close Window') ) |n %></a>
        </div>

        <& /Elements/MessageBox,
            Name => 'Comment',
            Type => 'text/plain',
            Height => 3,
            Width => undef, # sets width:100% CSS
            Placeholder => loc('Comments for the ticket'),
            SuppressAttachmentWarning => 1,
            IncludeSignature => 0,
            IncludeArticle => 0,
        &>
    </div>

    <div class="extra ticket-timer-started"><&|/l, $Now->AsString &>Started [_1].</&></div>

% if ($Ticket->TimeEstimated) {
  <& /Elements/LabeledValue, Class => "time estimated",Label => loc("Estimated"), ValueSpanClass => "current-value", RawValue => $m->scomp("/Ticket/Elements/ShowTime", minutes => $Ticket->TimeEstimated) &>
% }

    <div class="on-error"><&|/l&>An error occurred while submitting time. Please submit your time manually.</&></div>

</div>

% $m->abort();
