Compare commits

...

110 Commits

Author SHA1 Message Date
Gregory Trullemans 2b5bd18ae5 Add tests views 2024-05-20 16:39:01 +02:00
Gregory Trullemans 0aa314b4e1 Add test and minor update. 2024-05-20 16:21:39 +02:00
Gregory Trullemans 2f1a0365e3 Add new tests, fix some tests and update some tests. 2024-05-19 19:38:21 +02:00
Gregory Trullemans ca629fd1fb Update chrono details add function 2024-05-18 13:23:58 +02:00
Gregory Trullemans 05e130355a Update chrono details form 2024-05-18 13:22:17 +02:00
Gregory Trullemans 9a60aac062 Update routine statistics buttons 2024-05-15 11:52:19 +02:00
Gregory Trullemans 8396b256c0 Interface update 2024-05-15 11:36:23 +02:00
Gregory Trullemans a6dbcb002c Update interface 2024-05-15 09:20:18 +02:00
Gregory Trullemans 53ea259b63 Update interface 2024-05-15 09:04:35 +02:00
Gregory Trullemans 60325b2ed3 Update interface buttons 2024-05-15 08:51:02 +02:00
Gregory Trullemans 270ef34582 Minor update 2024-05-14 15:20:17 +02:00
Gregory Trullemans 8915a390f3 Minor update 2024-05-14 12:18:46 +02:00
Gregory Trullemans 0541fa6be3 update gymnast event/note tab 2024-05-14 10:33:27 +02:00
Gregory Trullemans 99cd1d01e6 Bug fix 2024-05-14 10:06:31 +02:00
Gregory Trullemans 5e3b4222cd Update dashboard 2024-05-13 14:18:22 +02:00
Gregory Trullemans 2827ca9669 Bug fix 2024-05-13 14:13:38 +02:00
Gregory Trullemans b8fa28d225 Update Dashboard for gymnast: add link 2024-05-11 08:41:29 +01:00
Gregory Trullemans cef1893333 Update dashboard for gymnast. 2024-05-10 20:53:02 +01:00
Gregory Trullemans a10df7b3d2 Bug fix into dashboard 2024-05-09 20:41:08 +01:00
Gregory Trullemans c910374a1b Update gymnast dashboard 2024-05-09 20:38:23 +01:00
Gregory Trullemans 4ec24b630d Update to follow GDPR 2024-05-07 11:02:45 +02:00
Gregory Trullemans 40ab04a823 Update trainers/gymnasts link 2024-05-06 15:01:55 +02:00
Gregory Trullemans a811688cf4 Fix bug into gymnast details function. 2024-05-05 19:32:35 +02:00
Gregory Trullemans 264dc148f1 Update gitignore 2024-05-05 16:19:08 +02:00
Gregory Trullemans f2574755a3 Update Dashboard 2024-05-05 13:26:05 +02:00
Gregory Trullemans 50c03271c5 Bug fix on date for tablesorter 2024-05-05 12:58:50 +02:00
Gregory Trullemans f89dffbc79 Fix bug with select into form (re-add popper.js) 2024-05-04 19:50:10 +02:00
Gregory Trullemans 54b196cafd Bug fix in gymnast details listing (wellbeing, …) 2024-05-04 19:35:50 +02:00
Gregory Trullemans 2c31bc66b1 Bug fix in chrono listing 2024-05-04 19:29:30 +02:00
Gregory Trullemans 89549e22e7 Bug fix in gymnast listing function 2024-05-04 08:02:34 +02:00
Gregory Trullemans fc5a443b32 Update dashboard 2024-05-02 10:23:12 +02:00
Gregory Trullemans 04722582ec Add migration file 2024-05-01 17:29:03 +02:00
Gregory Trullemans e20876e26d update right maangement 2024-05-01 16:57:15 +02:00
Gregory Trullemans be99b8e37f Add js cor elibrary 2024-05-01 14:21:44 +02:00
Gregory Trullemans 8c46fd750d Remove JS libraries 2024-05-01 14:20:09 +02:00
Gregory Trullemans 0c4bdcc738 Remove JS Libraries 2024-05-01 13:59:10 +02:00
Gregory Trullemans ed0e712d1a Use CDN and remove JS local libraries 2024-05-01 13:47:57 +02:00
Gregory Trullemans ab8bcb8d0d Lots of minor improvements 2024-04-30 08:31:32 +02:00
Gregory Trullemans cfef189b1c Lot of modifications 2024-04-29 12:55:05 +02:00
Gregory Trullemans aeb07ccb01 Improve gymanst<->trainers link 2024-04-24 14:17:51 +02:00
Gregory Trullemans 47d3581fee Fig bug in season information UI form 2024-04-24 11:42:38 +02:00
Gregory Trullemans 9a127cfb87 Add gymnast trainer management. 2024-04-24 10:04:37 +02:00
Gregory Trullemans 0f2fcda740 Remove unused JS Library and prune BlackDashboard CSS. 2024-04-23 11:40:36 +02:00
Gregory Trullemans 6084bfd15e Update ChartJS, update jquery, … 2024-04-23 10:15:36 +02:00
Gregory Trullemans 0687b57e12 Update wellbeing form/ui 2024-04-22 15:27:12 +02:00
Gregory Trullemans ff9bb5f7f9 Update Mindstate form interface 2024-04-22 14:37:36 +02:00
Gregory Trullemans 2bfa728daa Update Mindstate form interface 2024-04-22 10:57:32 +02:00
Gregory Trullemans a908bacfa9 Update Mindstate form interface 2024-04-22 10:55:20 +02:00
Gregory Trullemans c2d8fca40e Update mindstate form 2024-04-22 10:36:30 +02:00
Gregory Trullemans 84427a49f0 Minor updates 2024-04-21 18:37:20 +02:00
Gregory Trullemans ccc33efbba Update FullCalendar library 2024-04-21 12:39:33 +02:00
Gregory Trullemans 0e10b2f9d4 Update D3 library 2024-04-21 07:31:55 +02:00
Gregory Trullemans 9eaacdc9b0 Update DataTables javascript 2024-04-20 20:00:53 +02:00
Gregory Trullemans 0097cdc5d8 Close #5 2024-04-20 19:39:34 +02:00
Gregory Trullemans 68fcc83037 Update interface 2024-04-20 19:28:46 +02:00
Gregory Trullemans 2111a1367a Update interface 2024-04-20 19:25:43 +02:00
Gregory Trullemans 1fe9e31066 Update JS script 2024-04-20 19:10:13 +02:00
Gregory Trullemans 6b43ed7bc1 Update interface 2024-04-20 18:44:32 +02:00
Gregory Trullemans 9a9af8269d Update interface 2024-04-20 16:51:31 +02:00
Gregory Trullemans 8e7ac42412 Update interface 2024-04-20 16:47:16 +02:00
Gregory Trullemans ea58a90f3f Update button's interface 2024-04-20 16:14:31 +02:00
Gregory Trullemans 193c27641c Improve UI for smartphone 2024-04-20 14:45:23 +02:00
Gregory Trullemans 0c98a8d3db Update button's interface 2024-04-20 13:51:22 +02:00
Gregory Trullemans 48062fbc5b Minor update on gymnast details 2024-04-19 14:41:16 +02:00
Gregory Trullemans 20293fbab7 Improve security and minor improvement 2024-04-19 11:01:23 +02:00
Gregory Trullemans 170eecd104 Minor interface update 2024-04-19 09:32:41 +02:00
Gregory Trullemans 814eb60a11 Periodical report bug fix 2024-04-18 17:39:32 +02:00
Gregory Trullemans e05f23febe URL bug fix 2024-04-18 17:34:32 +02:00
Gregory Trullemans f49fbcae3f URL bug fix 2024-04-18 17:33:59 +02:00
Gregory Trullemans de6a7b62dc Lots of update and bug fix. 2024-04-18 17:10:10 +02:00
Gregory Trullemans 4481e35b05 Add personnal best in chrono listing. 2024-04-17 14:41:05 +02:00
Gregory Trullemans 4b6f33c306 Add season informations details 2024-04-17 10:12:06 +02:00
Gregory Trullemans 8ab21746fa Fix season information form bug 2024-04-17 08:32:28 +02:00
Gregory Trullemans 65403d79dd Fix season_information.category bug 2024-04-16 12:38:55 +02:00
Gregory Trullemans f887477421 Update model 2024-04-16 11:18:00 +02:00
Gregory Trullemans 015b89466e Add filter to CompetitionCategory model 2024-04-16 11:09:25 +02:00
Gregory Trullemans 46bc94bed1 [WIP] Update models 2024-04-16 11:01:21 +02:00
Gregory Trullemans 81727fbdf8 Update models 2024-04-16 10:48:34 +02:00
Gregory Trullemans fd6dcb56a4 Update gymnast details interface 2024-04-15 12:17:33 +02:00
Gregory Trullemans 6eecd9fa5d Improve help page and search 2024-04-15 11:23:18 +02:00
Gregory Trullemans adbdf5eebc Update help page 2024-04-15 09:14:13 +02:00
Gregory Trullemans d1d1a5a695 Add informations and image to help page. 2024-04-14 13:01:08 +02:00
Gregory Trullemans e7e70070d7 Update help page 2024-04-13 18:54:34 +02:00
Gregory Trullemans a62fd2ddee Bug fix in chrono listing 2024-04-13 07:40:29 +02:00
Gregory Trullemans e478bcd6a4 User manual improvement 2024-04-12 16:06:22 +02:00
Gregory Trullemans d3e64453be Improve help page 2024-04-11 20:43:35 +02:00
Gregory Trullemans 84bdffeee5 Improve help page 2024-04-11 19:51:19 +02:00
Gregory Trullemans 1574f3ce16 Add user manual for all user 2024-04-11 18:48:36 +02:00
Gregory Trullemans 4a8c483ac1 Update HTML listing 2024-04-11 16:46:44 +02:00
Gregory Trullemans 51932230f1 Align graph in listing 2024-04-11 16:41:15 +02:00
Gregory Trullemans c3d34fe174 Update chrono add and list management 2024-04-11 16:29:15 +02:00
Gregory Trullemans 514807204a Add graph into gymnast chrono listing 2024-04-11 12:18:14 +02:00
Gregory Trullemans 8612ea9087 Add BMI to height/weight graph 2024-04-11 08:42:03 +02:00
Gregory Trullemans adaa3fe0e3 Minor optimisation 2024-04-10 14:14:06 +02:00
Gregory Trullemans 222cf41a95 Update wellbeing listing for a gymnast 2024-04-10 14:02:46 +02:00
Gregory Trullemans c3cde290e9 New height/weight list for gymnast 2024-04-10 12:15:20 +02:00
Gregory Trullemans 9f889f27be Fix bug in records 10 straightjumps 2024-04-10 09:49:28 +02:00
Gregory Trullemans 6074f7b1a3 Minors improvements 2024-04-09 19:32:01 +02:00
Gregory Trullemans 0a27daad50 Category in bold 2024-04-09 10:47:54 +02:00
Gregory Trullemans 77a574b750 Add season informations tab template 2024-04-09 10:40:29 +02:00
Gregory Trullemans 5f968d7c03 Push Season Informations outside gymnast profil details 2024-04-09 10:37:18 +02:00
Gregory Trullemans c796262b54 Fix link from gymnast's note list to gymnast details 2024-04-07 19:45:39 +02:00
Gregory Trullemans 0d8dde8c0f Add link to gymnast notes listing 2024-04-07 18:53:32 +02:00
Gregory Trullemans 0dc55ab8b1 Add image for help 2024-04-05 13:07:46 +02:00
Gregory Trullemans 1b96659afb [WIP] Add user manual into jarvis 2024-04-05 13:00:17 +02:00
Gregory Trullemans 48fb5ee96e Bug fix on gymnast learning skills details 2024-04-04 17:10:59 +02:00
Gregory Trullemans bd024d4a73 Add minor improvement for smartphone screen 2024-04-02 17:17:47 +02:00
Gregory Trullemans 233d82d992 Bug fix on intensity tab. 2024-03-30 15:00:21 +01:00
Gregory Trullemans ce50f4d8f1 Bug fix 2024-03-29 15:25:32 +01:00
Gregory Trullemans 291b9db321 Remove Passe, TrainingPasse, … models 2024-03-25 13:10:29 +01:00
192 changed files with 5658 additions and 33037 deletions

5
.gitignore vendored
View File

@ -44,7 +44,8 @@ static/js/plugins/fullcalendar/locales-all.min.js
*.db
*.bkp
*.png
*.drawio*
*.docx
*.pdf
*.pdf
tested_solution*

View File

@ -14,3 +14,4 @@ class EmailAdmin(admin.ModelAdmin):
model = Email
list_display = ("title", "created_at", "updated_at", "sent_at", "last_tried_at")
search_fields = ("title",)

View File

@ -22,11 +22,11 @@
<!-- Fonts and icons -->
<link href="https://fonts.googleapis.com/css?family=Poppins:200,300,400,600,700,800" rel="stylesheet" />
<!-- Font Awesome Pro -->
<!-- Font Awesome -->
<link href="{% static "css/font_awesome_all_5.15.3.css" %}" rel="stylesheet" />
<!-- Full Calendar Plugin, full documentation here: https://github.com/fullcalendar/fullcalendar -->
<link href="{% static "js/plugins/fullcalendar/main.min.css" %}" rel="stylesheet" />
<!-- <link href="{% static "js/plugins/fullcalendar/main.min.css" %}" rel="stylesheet" /> -->
<!-- JQuery UI CSS -->
<link href="{% static "js/plugins/jqueryui/jquery-ui.theme.min.css" %}" rel="stylesheet" />
@ -38,23 +38,21 @@
<!-- CSS Files -->
<link href="{% static "css/black-dashboard.css" %}" rel="stylesheet" />
<!-- Maps by mapbox -->
<script src='https://api.mapbox.com/mapbox.js/v3.2.0/mapbox.js'></script>
<link href='https://api.mapbox.com/mapbox.js/v3.2.0/mapbox.css' rel='stylesheet' />
<!-- Core JS Files -->
<script src="{% static "js/core/jquery-3.6.0.min.js" %}"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- Popper.js - necessaire pour les SELECT, DATEPICKER, … -->
<script src="{% static "js/core/popper.min.js" %}"></script>
<script src="{% static "js/core/bootstrap.min.js" %}"></script>
<!-- Chart JS -->
<script src="{% static "js/plugins/momentjs/moment_2.29.1.min.js" %}"></script>
<script src="{% static "js/plugins/momentjs/moment_locale_en-gb.js" %}"></script>
<script src="{% static "js/plugins/chartjs/chartjs_3.9.1.min.js" %}"></script>
<script src="{% static "js/plugins/chartjs/chartjs-adapter-moment_1.0.0.js" %}"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/locale/en-gb.min.js" integrity="sha512-w+tDY4gx49+DNVlN7Nmc9ldOkh6nP3w4txBTEatSx3XrZdfYtX9+oylJjQ7RqeeDzDebG3u1VAg/gM5Td2Bd5Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="{% static "js/plugins/chartjs/chartjs_4.4.2.min.js" %}"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-adapter-moment/1.0.1/chartjs-adapter-moment.min.js" integrity="sha512-hVy4KxCKgnXi2ok7rlnlPma4JHXI1VPQeempoaclV1GwRHrDeaiuS1pI6DVldaj5oh6Opy2XJ2CTljQLPkaMrQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- DataTables -->
<link rel="stylesheet" href="https://cdn.datatables.net/2.0.5/css/dataTables.dataTables.min.css" crossorigin="anonymous" referrerpolicy="no-referrer" />
<!-- FullCalendar CSS -->
<!-- <link href="{% static "js/plugins/fullcalendar/main.css" %}" rel="stylesheet" /> -->
{% block header %}{% endblock %}
</head>
@ -93,13 +91,13 @@
</li>
{% menuitem 'next_event_list' 'fal fa-calendar-alt' 'Events' %}
{% if request.user|has_group:"trainer" %}
{% menuitem 'injuries_list' 'fal fa-comment-alt-medical' 'Injuries' %}
{% menuitem 'injury_list' 'fal fa-comment-alt-medical' 'Injuries' %}
{% endif %}
{% menuitem 'place_list' 'fal fa-map-marked-alt' 'Places' %}
{% if request.user|has_group:"trainer" %}
{% menuitem 'chrono_list' 'fal fa-stopwatch' 'Chronos' %}
{% endif %}
{% menuitem 'report' 'fal fa-file-contract' 'Reports' %}
{% menuitem 'report_listing' 'fal fa-file-contract' 'Reports' %}
{% if request.user.is_staff %}
<li>
<a href="/admin/" target="_blank">
@ -164,6 +162,9 @@
<a href="{% url 'notification_update' %}" class="nav-item dropdown-item"><i class="fal fa-envelope"></i>&nbsp;Notifications</a>
</li>
{% endif %}
<li class="nav-link">
<a href="{% url 'help' %}" class="nav-item dropdown-item"><i class="fal fa-hands-helping"></i>&nbsp;User Manual</a>
</li>
<li class="dropdown-divider"></li>
<li class="nav-link">
<a href="{% url 'logout' %}" class="nav-item dropdown-item"><i class="fal fa-sign-out-alt"></i>&nbsp;Log out</a>
@ -199,157 +200,60 @@
</div>
</div>
<script src="{% static "js/plugins/perfect-scrollbar.jquery_1.4.0.min.js" %}"></script>
<!-- Plugin for Switches, full documentation here: http://www.jque.re/plugins/version3/bootstrap.switch/ -->
<script src="{% static "js/plugins/bootstrap-switch_3.3.4.js" %}"></script>
<!-- Plugin for Sweet Alert -->
<script src="{% static "js/plugins/sweetalert2.min.js" %}"></script>
<!-- Plugin for Sorting Tables -->
<script src="{% static "js/plugins/jquery.tablesorter_2.0.5b.js" %}"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.1.6/js/jquery.tablesorter.min.js" integrity="sha512-PJohiaiphaWGCrCvLQa6YeMPfqbCkr0Pz6p0BEMrA3aLM/22Pq8ypOPTgrdunGNeMwkw3fEdwVauiyTeqELJ1Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- Forms Validations Plugin -->
<script src="{% static "js/plugins/jquery.validate_1.17.0.min.js" %}"></script>
<!-- Plugin for the Wizard, full documentation here: https://github.com/VinceG/twitter-bootstrap-wizard -->
<script src="{% static "js/plugins/jquery.bootstrap-wizard_1.4.2.js" %}"></script>
<!-- Plugin for Select, full documentation here: http://silviomoreto.github.io/bootstrap-select -->
<script src="{% static "js/plugins/bootstrap-selectpicker_1.12.4.js" %}"></script>
<!-- Plugin for the DateTimePicker, full documentation here: https://eonasdan.github.io/bootstrap-datetimepicker/ -->
<script src="{% static "js/plugins/bootstrap-datetimepicker_4.17.47.js" %}"></script>
<!-- DataTables.net Plugin, full documentation here: https://datatables.net/ -->
<script src="{% static "js/plugins/datatables/datatables_1.12.1.min.js" %}"></script>
<!-- Plugin for Tags, full documentation here: https://github.com/bootstrap-tagsinput/bootstrap-tagsinputs -->
<script src="{% static "js/plugins/bootstrap-tagsinput_0.8.0.js" %}"></script>
<!-- Plugin for Fileupload, full documentation here: http://www.jasny.net/bootstrap/javascript/#fileinput -->
<script src="{% static "js/plugins/jasny-bootstrap_3.1.3.min.js" %}"></script>
<!-- Full Calendar Plugin, full documentation here: https://github.com/fullcalendar/fullcalendar -->
<script src="{% static "js/plugins/fullcalendar/main.js" %}"></script>
<!-- Vector Map plugin, full documentation here: http://jvectormap.com/documentation/ -->
<script src="{% static "js/plugins/jquery-jvectormap_2.0.4.js" %}"></script>
<!-- Plugin for the Sliders, full documentation here: http://refreshless.com/nouislider/ -->
<script src="{% static "js/plugins/nouislider_11.1.0.min.js" %}"></script>
<!-- Notifications Plugin -->
<script src="{% static "js/plugins/bootstrap-notify_3.1.5.js" %}"></script>
<script src="https://cdn.datatables.net/2.0.5/js/dataTables.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- Control Center for Black Dashboard: parallax effects, scripts for the example pages etc -->
<script src="{% static "js/black-dashboard.js" %}"></script>
<script src="{% static "js/core/black-dashboard.js" %}"></script>
<!-- Jquery UI for autocomplete, etc. -->
<script src="{% static "js/plugins/jqueryui/jquery-ui.min.js" %}"></script>
<!-- <script src="{% static "js/plugins/jqueryui/jquery-ui.min.js" %}"></script> -->
<script src="https://code.jquery.com/ui/1.13.3/jquery-ui.min.js" integrity="sha256-sw0iNNXmOJbQhYFuC9OF2kOlD5KQKe1y5lfBn4C9Sjg=" crossorigin="anonymous"></script>
<script type="text/javascript">
$(document).ready(function() {
$().ready(function() {
$sidebar = $('.sidebar');
$navbar = $('.navbar');
$main_panel = $('.main-panel');
$full_page = $('.full-page');
$sidebar_responsive = $('body > .navbar-collapse');
$sidebar = $('.sidebar');
$navbar = $('.navbar');
$main_panel = $('.main-panel');
$full_page = $('.full-page');
$sidebar_responsive = $('body > .navbar-collapse');
{% if request.session.is_sidebar_minified %}sidebar_mini_active = true;
{% else %}sidebar_mini_active = false;
{% endif %}
{% if request.session.is_sidebar_minified %}sidebar_mini_active = true;
{% else %}sidebar_mini_active = false;
{% endif %}
{% if request.session.template == 0 %}white_color = false;
{% else %}white_color = true;
{% endif %}
{% if request.session.template == 0 %}white_color = false;
{% else %}white_color = true;
{% endif %}
window_width = $(window).width();
fixed_plugin_open = $('.sidebar .sidebar-wrapper .nav li.active a p').html();
window_width = $(window).width();
fixed_plugin_open = $('.sidebar .sidebar-wrapper .nav li.active a p').html();
{% if request.session.sidebar == 1 %}color = 'blue';
{% elif request.session.sidebar == 2 %}color = 'green';
{% elif request.session.sidebar == 3 %}color = 'orange';
{% elif request.session.sidebar == 4 %}color = 'red';
{% else %}color = 'purple'
{% endif %}
$sidebar.attr('data', color);
$main_panel.attr('data', color);
$full_page.attr('filter-color', color);
$sidebar_responsive.attr('data', color);
{% if request.session.sidebar == 1 %}color = 'blue';
{% elif request.session.sidebar == 2 %}color = 'green';
{% elif request.session.sidebar == 3 %}color = 'orange';
{% elif request.session.sidebar == 4 %}color = 'red';
{% else %}color = 'purple'
{% endif %}
$sidebar.attr('data', color);
$main_panel.attr('data', color);
$full_page.attr('filter-color', color);
$sidebar_responsive.attr('data', color);
// $('.fixed-plugin a').click(function(event) {
// if ($(this).hasClass('switch-trigger')) {
// if (event.stopPropagation) {
// event.stopPropagation();
// } else if (window.event) {
// window.event.cancelBubble = true;
// }
// }
// });
$('.light-badge').click(function() {
$('body').addClass('white-content');
});
// $('.fixed-plugin .background-color span').click(function() {
// $(this).siblings().removeClass('active');
// $(this).addClass('active');
// var new_color = $(this).data('color');
// if ($sidebar.length != 0)
// $sidebar.attr('data', new_color);
// if ($main_panel.length != 0)
// $main_panel.attr('data', new_color);
// if ($full_page.length != 0)
// $full_page.attr('filter-color', new_color);
// if ($sidebar_responsive.length != 0)
// $sidebar_responsive.attr('data', new_color);
// });
// $('.switch-sidebar-mini input').on("switchChange.bootstrapSwitch", function() {
// var $btn = $(this);
// if (sidebar_mini_active == true) {
// $('body').removeClass('sidebar-mini');
// sidebar_mini_active = false;
// blackDashboard.showSidebarMessage('Sidebar mini deactivated...');
// } else {
// $('body').addClass('sidebar-mini');
// sidebar_mini_active = true;
// blackDashboard.showSidebarMessage('Sidebar mini activated...');
// }
// // we simulate the window Resize so the charts will get updated in realtime.
// var simulateWindowResize = setInterval(function() {
// window.dispatchEvent(new Event('resize'));
// }, 180);
// // we stop the simulation of Window Resize after the animations are completed
// setTimeout(function() {
// clearInterval(simulateWindowResize);
// }, 1000);
// });
// $('.switch-change-color input').on("switchChange.bootstrapSwitch", function() {
// var $btn = $(this);
// if (white_color == true) {
// $('body').addClass('change-background');
// setTimeout(function() {
// $('body').removeClass('change-background');
// $('body').removeClass('white-content');
// }, 900);
// white_color = true; // false
// } else {
// $('body').addClass('change-background');
// setTimeout(function() {
// $('body').removeClass('change-background');
// $('body').addClass('white-content');
// }, 900);
// white_color = true;
// }
// });
$('.light-badge').click(function() {
$('body').addClass('white-content');
});
$('.dark-badge').click(function() {
$('body').removeClass('white-content');
});
// $('#searchModal').on('shown.bs.modal', function() {
// $('#inlineFormInputGroup').trigger('focus')
// });
$('.dark-badge').click(function() {
$('body').removeClass('white-content');
});
});
</script>

View File

@ -9,16 +9,16 @@
<div class="col-md-3">
<div class="card">
<div class="card-header">
<h4><i class="fal fa-quote-left text-danger"></i> Quote</h4>
<h4><i class="fal fa-quote-left text-danger"></i> Quote of the day</h4>
</div>
<div class="card-body text-justify">
<div class="card-body text-justify pt-0 pb-0">
{{ quote.to_markdown | safe }}
</div>
{% if quote.author %}
<div class="card-footer text-right text-muted">
<div class="card-footer pt-0 text-right text-muted">
{% if quote.author %}
<i>{{ quote.author }}</i>
</div>
{% endif %}
{% endif %}
</div>
</div>
</div>
<div class="col-md-6">
@ -27,9 +27,8 @@
<h4 class=""><i class="text-primary fal fa-laugh-wink"></i> Hi {{ user.first_name }} !</h4>
</div>
<div class="card-body text-justify pt-0">
<p>Welcome to Jarvi v0.96.3 <span class="text-muted">(last update : 21-3-2024)</span></p>
<p>This application is here to help coaches to manage the gymnasts (evolution, evaluation, routines, scores, …). This tool is not perfect so feel free to make improvement proposals, bug reports, … by sending me an <a href="mailto:gregory@flyingacrobaticstrampoline.be">email</a>.</p>
<p>You can find the user manual <a href="{% static "files/Manuel_Utilisateur.pdf" %}" download>here (in french)</a>.</p>
<p>Welcome to Jarvi v1.0.5 <span class="text-muted">(last update : 14 may 2024)</span>.</p>
<p>This application is designed to assist coaches in managing gymnasts' progress, evaluations, routines, scores, and more. While this tool isn't flawless, please feel free to submit improvement suggestions, bug reports, or any feedback by sending an <a href="mailto:gregory@flyingacrobaticstrampoline.be?subject=Jarvis remarks">email</a>.</p>
</div>
</div>
</div>
@ -51,7 +50,8 @@
<div class="row">
<div class="col-md-7">
<ul class="list-unstyled mb-0">
{% if nb_active_gymnast %}<li>{{ nb_active_gymnast }} active gymnasts</li>{% endif %}
<li>{{ nb_active_gymnast }} active gymnasts</li>
<li>{{ nb_trainer }} active trainers</li>
{% if nb_event %}<li>{{ nb_event }} events</li>{% endif %}
{% if nb_score %}<li>{{ nb_score }} scores</li>{% endif %}
</ul>
@ -89,10 +89,11 @@
<td class="text-left"><a href="{% url 'event_details' event.id %}">{{ event.name }}</a></td>
<td>
{% if event.number_of_week_from_today < 0 %}
{{event.number_of_week_from_today}}
{{ event.number_of_week_from_today }}
{% else %}
<span class="text-{% if event.number_of_week_from_today > 12 %}success{% elif event.number_of_week_from_today > 9 %}info{% elif event.number_of_week_from_today > 6 %}warning{% else %}danger{% endif %}">
<b>{{event.number_of_week_from_today}}</b></span>
<b>{{ event.number_of_week_from_today }}</b>
</span>
{% endif %}
</td>
</tr>
@ -107,6 +108,7 @@
<div class="col-md-3">
<div class="card">
{% if is_trainer %}
<div class="card-header">
<h4><i class="fal fa-exclamation-triangle text-danger"></i> Updated needed</h4>
</div>
@ -124,10 +126,91 @@
No update needed.
{% endif %}
</div>
{% else %}
<div class="card-header">
<h4><i class="fal fa-exclamation-triangle text-danger"></i> Your last profile update</h4>
</div>
<div class="card-body pt-0">
<ol class="list-unstyled mb-0">
<li>
<a href="{% url 'wellbeing_create_for_gymnast' gymnast.id %}">Wellbeing</a>:
{% if wellbeing_state %}
<span class="text-{{ wellbeing_state }}">
{% endif %}
{% if wellbeing_last_record_date %}
{{ wellbeing_last_record_date.0 |date:"j F Y" }}
{% else %}
Never
{% endif %}
{% if wellbeing_state %}
</span>
{% endif %}
</li>
<li>
<a href="{% url 'heightweight_create_for_gymnast' gymnast.id %}">Height/Weight</a>:
{% if height_weight_state %}
<span class="text-{{ height_weight_state }}">
{% endif %}
{% if height_weight_last_record_date %}
{{ height_weight_last_record_date.0 |date:"j F Y" }}
{% else %}
Never
{% endif %}
{% if wellbeing_state %}
</span>
{% endif %}
</li>
<li>
<a href="{% url 'intensity_create_for_gymnast' gymnast.id %}">Intensity</a>:
{% if intensity_state %}
<span class="text-{{ intensity_state }}">
{% endif %}
{% if intensities_last_record_date %}
{{ intensities_last_record_date.0 |date:"j F Y" }}
{% else %}
Never
{% endif %}
{% if wellbeing_state %}
</span>
{% endif %}
</li>
<!-- <li>{{ points_last_update }}</li> -->
<li>
<a href="{% url 'chrono_create_for_gymnast' gymnast.id %}">Chrono</a>:
{% if chrono_state %}
<span class="text-{{ chrono_state }}">
{% endif %}
{% if chrono_last_record_date %}
{{ chrono_last_record_date.0 |date:"j F Y" }}
{% else %}
Never
{% endif %}
{% if chrono_state %}
</span>
{% endif %}
</li>
<li>
<a href="#">Learned Skill</a>:
{% if known_skills_state %}
<span class="text-{{ known_skills_state }}">
{% endif %}
{% if known_skills_last_record_date %}
{{ known_skills_last_record_date.0 |date:"j F Y" }}
{% else %}
Never
{% endif %}
{% if known_skills_state %}
</span>
{% endif %}
</li>
</ol>
</div>
{% endif %}
</div>
</div>
<div class="col-md-3">
{% if is_trainer %}
<div class="card">
<div class="card-header">
<h4><i class="fal fa-highlighter text-success"></i> Last updated gymnasts</h4>
@ -147,6 +230,7 @@
{% endif %}
</div>
</div>
{% endif %}
</div>
<div class="col-md-3">
@ -166,7 +250,7 @@
{% endfor %}
</table>
{% else %}
No next birtday (it's a bug).
<p class="text-muted">No next birtday (it's a bug).</p>
{% endif %}
</div>
</div>

File diff suppressed because it is too large Load Diff

View File

@ -33,7 +33,6 @@
<!-- <div class="flextable table-actions">
{% block under %}{% endblock %}
</div> -->
</div>
</div>
</div>
<!-- {% block pagination %}{% endblock %} -->

View File

@ -21,17 +21,10 @@
<!-- Fonts and icons -->
<link href="https://fonts.googleapis.com/css?family=Poppins:200,300,400,600,700,800" rel="stylesheet" />
<link href="https://use.fontawesome.com/releases/v5.0.6/css/all.css" rel="stylesheet" />
<!-- Nucleo Icons -->
<link href="{% static "css/nucleo-icons.css" %}" rel="stylesheet" />
<!-- CSS Files -->
<link href="{% static "css/black-dashboard.css" %}" rel="stylesheet" />
<!-- Chart JS -->
<script src="{% static "js/plugins/momentjs/moment_2.29.1.min.js" %}"></script>
<script src="{% static "js/plugins/momentjs/moment_locale_en-gb.js" %}"></script>
<script src="{% static "js/plugins/chartjs/chartjs_3.9.1.min.js" %}"></script>
<script src="{% static "js/plugins/chartjs/chartjs-adapter-moment_1.0.0.js" %}"></script>
</head>
<body>
@ -84,47 +77,19 @@
<div class="footer-content"></div>
</footer>
<script src="{% static "js/core/jquery-3.6.0.min.js" %}"></script>
<script src="{% static "js/core/popper.min.js" %}"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- <script src="{% static "js/core/popper.min.js" %}"></script> -->
<script src="{% static "js/core/bootstrap.min.js" %}"></script>
<script src="{% static "js/plugins/perfect-scrollbar.jquery_1.4.0.min.js" %}"></script>
<script src="{% static "js/plugins/momentjs/moment_2.29.1.min.js" %}"></script>
<!-- Plugin for Switches, full documentation here: http://www.jque.re/plugins/version3/bootstrap.switch/ -->
<script src="{% static "js/plugins/bootstrap-switch_3.3.4.js" %}"></script>
<!-- Plugin for Sweet Alert -->
<script src="{% static "js/plugins/sweetalert2.min.js" %}"></script>
<!-- Plugin for Sorting Tables -->
<script src="{% static "js/plugins/jquery.tablesorter_2.0.5b.js" %}"></script>
<!-- Forms Validations Plugin -->
<script src="{% static "js/plugins/jquery.validate_1.17.0.min.js" %}"></script>
<!-- Plugin for the Wizard, full documentation here: https://github.com/VinceG/twitter-bootstrap-wizard -->
<script src="{% static "js/plugins/jquery.bootstrap-wizard_1.4.2.js" %}"></script>
<!-- Plugin for Select, full documentation here: http://silviomoreto.github.io/bootstrap-select -->
<script src="{% static "js/plugins/bootstrap-selectpicker_1.12.4.js" %}"></script>
<!-- Plugin for the DateTimePicker, full documentation here: https://eonasdan.github.io/bootstrap-datetimepicker/ -->
<script src="{% static "js/plugins/bootstrap-datetimepicker_4.17.47.js" %}"></script>
<!-- DataTables.net Plugin, full documentation here: https://datatables.net/ -->
<script src="{% static "js/plugins/datatables/datatables_1.12.1.min.js" %}"></script>
<!-- Plugin for Tags, full documentation here: https://github.com/bootstrap-tagsinput/bootstrap-tagsinputs -->
<script src="{% static "js/plugins/bootstrap-tagsinput_0.8.0.js" %}"></script>
<!-- Plugin for Fileupload, full documentation here: http://www.jasny.net/bootstrap/javascript/#fileinput -->
<script src="{% static "js/plugins/jasny-bootstrap_3.1.3.min.js" %}"></script>
<!-- Full Calendar Plugin, full documentation here: https://github.com/fullcalendar/fullcalendar -->
<script src="{% static "js/plugins/fullcalendar/main.js" %}"></script>
<!-- Vector Map plugin, full documentation here: http://jvectormap.com/documentation/ -->
<script src="{% static "js/plugins/jquery-jvectormap_2.0.4.js" %}"></script>
<!-- Plugin for the Sliders, full documentation here: http://refreshless.com/nouislider/ -->
<script src="{% static "js/plugins/nouislider_11.1.0.min.js" %}"></script>
<!-- Google Maps Plugin -->
<!-- Place this tag in your head or just before your close body tag. -->
<!-- <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_KEY_HERE"></script> -->
<!-- Notifications Plugin -->
<script src="{% static "js/plugins/bootstrap-notify_3.1.5.js" %}"></script>
<!-- Control Center for Black Dashboard: parallax effects, scripts for the example pages etc -->
<script src="{% static "js/black-dashboard.min.js" %}"></script>
<script src="{% static "js/core/black-dashboard.js" %}"></script>
<!-- Jquery UI for autocomplete, etc. -->
<script src="https://code.jquery.com/ui/1.13.3/jquery-ui.min.js" integrity="sha256-sw0iNNXmOJbQhYFuC9OF2kOlD5KQKe1y5lfBn4C9Sjg=" crossorigin="anonymous"></script>
<script type="text/javascript" >
<script type="text/japrintvascript" >
$(function(){
$('#login').focus();
});

View File

@ -20,7 +20,7 @@
<!-- Fonts and icons -->
<link href="https://fonts.googleapis.com/css?family=Poppins:200,300,400,600,700,800" rel="stylesheet" />
<!-- Font Awesome Pro -->
<link href="{% static "css/gymnast_report.css" %}" rel="stylesheet" />
<link href="{% static "css/a4_paper.css" %}" rel="stylesheet" />
<link href="{% static "css/font_awesome_all_5.15.3.css" %}" rel="stylesheet" />
<link href="{% static "css/black-dashboard_report.css" %}" rel="stylesheet" />
</head>
@ -50,7 +50,9 @@
</div>
<div class="col-6 pl-0">
{% for record in records_list %}
<h3 class="ml-3">{{ record.score }} - {{ record.first_name }} {{ record.last_name }} ({{ record.date| date:"j M Y" }})</h3>
{% if record.score %}
<h3 class="ml-3">{{ record.score }} - {{ record.first_name }} {{ record.last_name }} ({{ record.date| date:"j M Y" }})</h3>
{% endif %}
{% endfor %}
</div>
<div class="col-6 pl-0">

View File

@ -7,8 +7,9 @@
{% block content %}
<div class="card mb-0">
{% if gymnast_list or skill_list or event_list or place_list or club_list %}
{% if gymnast_list %}
<div class="card-header">
<h2>Search results</h2>
{% if gymnast_list %}
<h4 class="mb-0"> Gymnasts results</h4>
</div>
<div class="card-body pt-0 pb-1">
@ -38,11 +39,9 @@
</tbody>
</table>
</div>
</div>
{% endif %}
{% if skill_list %}
<div class="card-header">
<h4 class="mb-0"> Skills results</h4>
</div>
<div class="card-body pt-0 pb-1">
@ -52,8 +51,8 @@
<tr>
<th class="text-left">&nbsp;Long Label</th>
<th class="text-left">&nbsp;Short Label</th>
<th class="text-center">&nbsp;Age Girl</th>
<th class="text-center">&nbsp;Age Boy</th>
<th class="text-center"><i class="far fa-venus"></i></th>
<th class="text-center"><i class="far fa-mars"></i></th>
<th class="text-center">Notation</th>
<th class="header text-center">Diff.</th>
<th class="header text-center">Level</th>
@ -80,7 +79,6 @@
{% endif %}
{% if event_list %}
<div class="card-header">
<h4 class="mb-0"> Events results</h4>
</div>
<div class="card-body pt-0 pb-1">
@ -112,7 +110,6 @@
{% endif %}
{% if place_list %}
<div class="card-header">
<h4 class="mb-0"> Places results</h4>
</div>
<div class="card-body pt-0 pb-1">
@ -148,7 +145,6 @@
{% endif %}
{% if club_list %}
<div class="card-header">
<h4 class="mb-0"> Clubs results</h4>
</div>
<div class="card-body pt-0 pb-1">
@ -194,7 +190,7 @@
headers: {
0: { sorter: false }, // disable first column
},
dateFormat: "uk",
dateFormat : "ddmmyyyy",
sortList: [[1,0], [2,0]]
})
@ -223,7 +219,7 @@
headers: {
0: { sorter: false }, // disable first column
},
dateFormat: "uk",
dateFormat : "ddmmyyyy",
sortList: [[3,1], [1,0]]
});
@ -238,7 +234,7 @@
headers: {
0: { sorter: false }, // disable first column
},
dateFormat: "uk",
dateFormat : "ddmmyyyy",
sortList: [[3,0], [1,0]]
});

View File

@ -6,7 +6,7 @@ from django.urls import reverse
USER = get_user_model()
class HomeTests(TestCase):
class HomePageTests(TestCase):
def setUp(self):
self.user = USER.objects.create(
username="jbond", email="james@hms.co.uk", password="007"

View File

@ -0,0 +1,39 @@
from django.test import TestCase
from jarvis.core.models import Citation, Email
import markdown
class CitationModelTests(TestCase):
def test_citation_str(self):
"""Test the __str__ method to ensure it returns the correct string representation of a Citation instance."""
citation = Citation(
quote="Be yourself; everyone else is already taken.",
author="Oscar Wilde"
)
citation.save()
expected_str = "Be yourself; everyone else is already taken. - Oscar Wilde"
self.assertEqual(str(citation), expected_str, "The __str__ method does not return the expected string.")
def test_to_markdown(self):
"""Test the to_markdown method to ensure it correctly converts the quote to Markdown."""
citation = Citation(
quote="**Bold** text and _italic_ text."
)
citation.save()
expected_markdown = markdown.markdown(citation.quote)
self.assertEqual(citation.to_markdown(), expected_markdown, "The to_markdown method does not return the expected Markdown string.")
class EmailModelTests(TestCase):
def test_email_str(self):
"""Test the __str__ method to ensure it returns the correct string representation of an Email instance."""
email = Email(
title="Meeting Reminder",
receivers="john@example.com, jane@example.com"
)
email.save()
expected_str = "`Meeting Reminder` sent to john@example.com, jane@example.com"
self.assertEqual(str(email), expected_str, "The __str__ method does not return the expected string.")

View File

@ -6,6 +6,7 @@ from .views import (
home,
search,
report_listing,
help_view,
generate_best_straightjump_listing,
)
@ -19,10 +20,11 @@ urlpatterns = [
path(
r"core/report/",
report_listing,
name="report",
name="report_listing",
),
path(r"search/", search, name="global_search"),
path(r"login/", login, name="login"),
path(r"logout/", logout, name="logout"),
path(r"help/", help_view, name="help"),
path(r"", home, name="home"),
]

View File

@ -1,7 +1,11 @@
from datetime import timedelta
from weasyprint import HTML, CSS
import pendulum
from django.db.models import Max
from django.conf import settings
from django.db.models import Q, F, OuterRef, Subquery
from django.shortcuts import render
from django.shortcuts import render, get_object_or_404
from django.utils import timezone
from django.contrib.auth import authenticate, login as auth_login, logout as auth_logout
from django.http import HttpResponse, HttpResponseRedirect
@ -9,24 +13,30 @@ from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_http_methods
from django.template.loader import render_to_string
from django.urls import reverse
from django.contrib.auth import get_user_model
from jarvis.objective.models import Routine
from jarvis.profiles.models import Profile
from jarvis.followup.models import Skill, Point, Chrono
from jarvis.followup.models import (
Skill,
Point,
Chrono,
WellBeing,
Intensity,
HeightWeight,
LearnedSkill
)
from jarvis.location.models import Place, Club
from jarvis.people.models import Gymnast
from jarvis.people.views import gymnast_details
from jarvis.planning.models import Event
from django.db.models import Max
from django.conf import settings
from .models import Citation
from jarvis.tools.models import from_date_to_week_number
from jarvis.tools.clean_name import clean_name
from jarvis.tools.models import Season
from weasyprint import HTML, CSS
import pendulum
from .models import Citation
User = get_user_model()
def login(request):
@ -51,20 +61,7 @@ def login(request):
except Profile.DoesNotExist:
pass
available_gymnast = []
gymnast_list = user.gymnasts.all()
for gymnast in gymnast_list:
available_gymnast.append(gymnast.id)
try:
available_gymnast.append(user.gymnast.id)
except Gymnast.DoesNotExist:
pass
request.session["available_gymnast"] = available_gymnast
# request.session["clubid"] = request.POST.get("clubid", None)
request.session["available_gymnast"] = [x.gymnast.id for x in user.can_view.all()]
return HttpResponseRedirect(reverse("home"))
context = {"message": "Account disabled."}
@ -96,11 +93,33 @@ def next_birthdays(request, number_of_birthday):
return birthday_list
def gymnast_have_birthday(request):
"""
Renvoie la liste des gymnastes qui ont leur anniversaire aujourd'hui.
"""
today = pendulum.now().date()
return Gymnast.objects.filter(birthdate__day=today.day, birthdate__month=today.month).values_list("id")
# @lru_cache()
# def get_last_updated_gymnasts(expiration_date):
# ...
# TODO: liste de mots pour souhaiter la bienvenue
# TODO: véririer si c'est l'anniversaire de la personne qui est connectée.
# TODO: check if gymnast have point
# ---------------------------
# 1. récupérer tous les évènements passés
# 2. pour chaque event, vérifier que tous les gymnastes renseignés
# dans les participants ont des points associés.
# S'il n'y a pas de point, faire une alerte à l'utilisateur qui se connecte.
# TODO: Check if gymnast have update
# -----------------------------
# lister tous les gymnastes qui n'ont pas eu d'update depuis... 2 semaines ?
# peut-être le paramètre (en jour) devrait être stocké en DB.
# S'il n'y a pas d'update, faire une alerte à l'utilisateur qui se connecte.
@login_required
@require_http_methods(["GET"])
def home(request):
@ -109,95 +128,143 @@ def home(request):
"""
today = timezone.now() # pendulum.now().date()
_, week_number = from_date_to_week_number(today)
event_list = Event.objects.filter(date_begin__gte=today).order_by("date_begin")[:10]
quote = Citation.objects.order_by("?").first()
# A METTRE EN CACHE.
# last_updated_gymnast = None
last_updated_gymnasts = set()
last_updated_gymnasts.update(
Gymnast.objects.filter(wellbeings__created_at__gt=request.user.last_login)
)
last_updated_gymnasts.update(
Gymnast.objects.filter(height_weight__date__gt=request.user.last_login)
)
last_updated_gymnasts.update(
Gymnast.objects.filter(intensities__date__gt=request.user.last_login)
)
last_updated_gymnasts.update(
Gymnast.objects.filter(points__created_at__gt=request.user.last_login)
)
last_updated_gymnasts.update(
Gymnast.objects.filter(chronos__created_at__gt=request.user.last_login)
)
last_updated_gymnasts.update(
Gymnast.objects.filter(injuries__created_at__gt=request.user.last_login)
)
last_updated_gymnasts.update(
Gymnast.objects.filter(known_skills__created_at__gt=request.user.last_login)
)
season = Season()
# Paramètre dans le fichier .env ?
limit_date = today - timedelta(days=7)
waiting_update_gymnast = (
Gymnast.objects.filter(season_informations__season=season)
.exclude(
Q(is_active=False)
| Q(wellbeings__created_at__gte=limit_date)
| Q(points__created_at__gte=limit_date)
| Q(chronos__created_at__gte=limit_date)
| Q(injuries__created_at__gte=limit_date)
| Q(known_skills__created_at__gte=limit_date)
)
.distinct()
)
nb_active_gymnast = Gymnast.objects.filter(is_active=True).count()
nb_event = Event.objects.all().count()
nb_skill = Skill.objects.all().count()
nb_routine = Routine.objects.all().count()
nb_score = Point.objects.all().count()
nb_club = Club.objects.all().count()
# percentage_week = int(
# (get_number_of_weeks_between(datetime(2021, 9, 1), datetime.now()) / 52) * 100
# )
percentage_week = (week_number / 52) * 100
birthday_list = next_birthdays(request, 10)
# # check if gymnast have point
# # ---------------------------
# # 1. récupérer tous les évènements passés
# # 2. pour chaque event, vérifier que tous les gymnastes renseignés
# # dans les participants ont des points associés.
# # S'il n'y a pas de point, faire une alerte à l'utilisateur qui se connecte.
# # Check if gymnast have update
# # -----------------------------
# # lister tous les gymnastes qui n'ont pas eu d'update depuis... 2 semaines ?
# # peut-être le paramètre (en jour) devrait être stocké en DB.
# # S'il n'y a pas d'update, faire une alerte à l'utilisateur qui se connecte.
context = {
"quote": quote,
"week_number": week_number,
"event_list": event_list,
"last_updated_gymnasts": last_updated_gymnasts,
"waiting_update_gymnast": waiting_update_gymnast,
"nb_active_gymnast": nb_active_gymnast,
"nb_event": nb_event,
"nb_skill": nb_skill,
"nb_routine": nb_routine,
"nb_score": nb_score,
"nb_club": nb_club,
"percentage_week": percentage_week,
"birthday_list": birthday_list,
"quote": Citation.objects.order_by("?").first(),
"event_list": Event.objects.filter(date_begin__gte=today).order_by("date_begin")[:10],
"nb_active_gymnast": Gymnast.objects.filter(is_active=True).count(),
"nb_trainer": User.objects.filter(is_active=True, groups__name="trainer").count(),
"nb_event": Event.objects.all().count(),
"nb_skill": Skill.objects.all().count(),
"nb_routine": Routine.objects.all().count(),
"nb_score": Point.objects.all().count(),
"nb_club": Club.objects.all().count(),
"percentage_week": (week_number / 52) * 100,
"birthday_list": next_birthdays(request, 10),
}
is_trainer = request.user.groups.filter(name="trainer").exists()
if is_trainer:
last_updated_gymnasts = set()
last_updated_gymnasts.update(
Gymnast.objects.filter(wellbeings__created_at__gt=request.user.last_login)
)
last_updated_gymnasts.update(
Gymnast.objects.filter(height_weight__date__gt=request.user.last_login)
)
last_updated_gymnasts.update(
Gymnast.objects.filter(intensities__date__gt=request.user.last_login)
)
last_updated_gymnasts.update(
Gymnast.objects.filter(points__created_at__gt=request.user.last_login)
)
last_updated_gymnasts.update(
Gymnast.objects.filter(chronos__created_at__gt=request.user.last_login)
)
last_updated_gymnasts.update(
Gymnast.objects.filter(injuries__created_at__gt=request.user.last_login)
)
last_updated_gymnasts.update(
Gymnast.objects.filter(known_skills__created_at__gt=request.user.last_login)
)
season = Season()
# Paramètre dans le fichier .env ?
limit_date = today - timedelta(days=7)
waiting_update_gymnast = (
Gymnast.objects.filter(season_informations__season=season)
.exclude(
Q(is_active=False)
| Q(wellbeings__created_at__gte=limit_date)
| Q(points__created_at__gte=limit_date)
| Q(chronos__created_at__gte=limit_date)
| Q(injuries__created_at__gte=limit_date)
| Q(known_skills__created_at__gte=limit_date)
)
.distinct()
)
context["is_trainer"] = is_trainer
context["last_updated_gymnasts"] = last_updated_gymnasts
context["waiting_update_gymnast"] = waiting_update_gymnast
else:
todate = pendulum.now().date()
birthday_list = gymnast_have_birthday(request)
gymnast = get_object_or_404(Gymnast, pk=request.user.gymnast.id)
context["gymnast"] = gymnast
# if birthday_list is not None and gymnast.id in birthday_list:
# print("C'est l'anniversaire du gymnaste !")
# else:
# print("Pas son annif…")
wellbeing_last_record_date = WellBeing.objects.filter(gymnast=gymnast).values_list("date").order_by("-date").first()
wellbeing_state = None
if wellbeing_last_record_date:
if todate.diff(wellbeing_last_record_date[0]).in_days() > 21:
wellbeing_state = "danger bold"
elif todate.diff(wellbeing_last_record_date[0]).in_days() > 14:
wellbeing_state = "danger"
elif todate.diff(wellbeing_last_record_date[0]).in_days() > 7:
wellbeing_state = "warning"
height_weight_last_record_date = HeightWeight.objects.filter(gymnast=gymnast).values_list("date").order_by("-date").first()
height_weight_state = None
if height_weight_last_record_date:
if todate.diff(height_weight_last_record_date[0]).in_days() > 21:
height_weight_state = "danger bold"
elif todate.diff(height_weight_last_record_date[0]).in_days() > 14:
height_weight_state = "danger"
elif todate.diff(height_weight_last_record_date[0]).in_days() > 7:
height_weight_state = "warning"
intensities_last_record_date = Intensity.objects.filter(gymnast=gymnast).values_list("date").order_by("-date").first()
intensity_state = None
if intensities_last_record_date:
if todate.diff(intensities_last_record_date[0]).in_days() > 21:
intensity_state = "danger bold"
elif todate.diff(intensities_last_record_date[0]).in_days() > 14:
intensity_state = "danger"
elif todate.diff(intensities_last_record_date[0]).in_days() > 7:
intensity_state = "warning"
# points_last_update = Gymnast.objects.all().order_by("-date")[:1]
chrono_last_record_date = Chrono.objects.filter(gymnast=gymnast).values_list("date").order_by("-date").first()
chrono_state = None
if chrono_last_record_date:
if todate.diff(chrono_last_record_date[0]).in_days() > 21:
chrono_state = "danger bold"
elif todate.diff(chrono_last_record_date[0]).in_days() > 14:
chrono_state = "danger"
elif todate.diff(chrono_last_record_date[0]).in_days() > 7:
chrono_state = "warning"
known_skills_last_record_date = LearnedSkill.objects.filter(gymnast=gymnast).values_list("date").order_by("-date").first()
known_skills_state = None
if known_skills_last_record_date:
if todate.diff(known_skills_last_record_date[0]).in_days() > 21:
known_skills_state = "danger bold"
elif todate.diff(known_skills_last_record_date[0]).in_days() > 14:
known_skills_state = "danger"
elif todate.diff(known_skills_last_record_date[0]).in_days() > 7:
known_skills_state = "warning"
context["wellbeing_last_record_date"] = wellbeing_last_record_date
context["wellbeing_state"] = wellbeing_state
context["height_weight_last_record_date"] = height_weight_last_record_date
context["height_weight_state"] = height_weight_state
context["intensities_last_record_date"] = intensities_last_record_date
context["intensity_state"] = intensity_state
# "points_last_update": points_last_update,
context["chrono_last_record_date"] = chrono_last_record_date
context["chrono_state"] = chrono_state
context["known_skills_last_record_date"] = known_skills_last_record_date
context["known_skills_state"] = known_skills_state
return render(request, "dashboard/dashboard.html", context)
# return render(request, "dashboard/dashboard.html", {})
@login_required
@ -219,7 +286,9 @@ def search(request):
return gymnast_details(request, gymnast.id)
else:
skill_list = Skill.objects.filter(
Q(long_label__icontains=pattern) | Q(short_label__icontains=pattern)
Q(long_label__icontains=pattern)
| Q(short_label__icontains=pattern)
| Q(notation__icontains=pattern)
)
event_list = Event.objects.filter(
Q(name__icontains=pattern) | Q(place__name__icontains=pattern)
@ -246,13 +315,14 @@ def search(request):
return render(request, "search/results.html", context)
@login_required
@require_http_methods(["GET"])
def report_listing(request):
"""Liste des rapports disponibles"""
context = {}
return render(request, "reports/list.html", context)
return render(request, "reports/list.html", {})
@login_required
@require_http_methods(["GET"])
def generate_best_straightjump_listing(request):
"""Va chercher le meilleur chrono pour chaque gymnaste et sa date de réalisation pour en générer
un fichier PDF."""
@ -296,9 +366,15 @@ def generate_best_straightjump_listing(request):
HTML(string=html, base_url=request.build_absolute_uri()).write_pdf(
response,
stylesheets=[
CSS(settings.STATICFILES_DIRS[0] + "/css/gymnast_report.css"),
CSS(settings.STATICFILES_DIRS[0] + "/css/a4_paper.css"),
CSS(settings.STATICFILES_DIRS[0] + "/css/black-dashboard_report.css"),
CSS(settings.STATICFILES_DIRS[0] + "/css/font_awesome_all_5.15.3.css"),
],
) # , font_config=font_config)
return response
@login_required
@require_http_methods(["GET"])
def help_view(request):
""" Appel à la vue d'aide. """
return render(request, "help/help.html", {})

View File

@ -19,6 +19,7 @@ from .models import (
ChronoDetails,
GymnastHasRoutine,
SeasonInformation,
CompetitionCategory,
NumberOfRoutineDone,
CompetitivePointsStats,
)
@ -272,7 +273,7 @@ class SeasonInformationAdmin(admin.ModelAdmin):
list_display = (
"gymnast",
"season",
"category",
# "category",
"number_of_training_sessions_per_week",
"number_of_hours_per_week",
"number_of_s_and_c_sessions_per_week",
@ -303,3 +304,26 @@ class CompetitivePointsStatsAdmin(admin.ModelAdmin):
("statistic_type", ChoiceDropdownFilter),
("routine_type", ChoiceDropdownFilter), # A supprimer ?
)
@admin.register(CompetitionCategory)
class CompetitionCategoryAdmin(admin.ModelAdmin):
model = CompetitionCategory
fields = (
"long_label",
"short_label",
"age_min",
"age_max",
"informations",
)
list_display = (
"long_label",
"short_label",
"age_min",
"age_max",
)
list_filter = (
"age_min",
"age_max",
)

View File

@ -187,6 +187,7 @@ class InjuryForm(forms.ModelForm):
fields = (
"gymnast",
"date",
"skill",
"mechanism",
"injury_type",
"location",
@ -267,42 +268,47 @@ class WellBeingForm(forms.ModelForm):
"event": forms.HiddenInput(),
"mindstate": forms.NumberInput(
attrs={
"type": "range",
"min": 1,
"max": 10,
"step": 1,
"class": "form-control",
"placeholder": "x",
"min": "0",
"max": "10",
}
),
"sleep": forms.NumberInput(
attrs={
"class": "form-control",
"placeholder": "x",
"min": "0",
"type": "range",
"min": "1",
"max": "10",
"step": "1",
"class": "form-control",
}
),
"stress": forms.NumberInput(
attrs={
"class": "form-control",
"placeholder": "x",
"min": "0",
"type": "range",
"min": "1",
"max": "10",
"step": "1",
"class": "form-control rtl",
}
),
"fatigue": forms.NumberInput(
attrs={
"class": "form-control",
"placeholder": "x",
"min": "0",
"type": "range",
"min": "1",
"max": "10",
"step": "1",
"class": "form-control rtl",
}
),
"muscle_soreness": forms.NumberInput(
attrs={
"class": "form-control",
"placeholder": "x",
"min": "0",
"type": "range",
"min": "1",
"max": "10",
"step": "1",
"class": "form-control rtl",
}
),
"informations": forms.Textarea(
@ -705,7 +711,7 @@ class IntensityForm(forms.ModelForm):
"informations": forms.Textarea(
attrs={
"class": "form-control",
"placeholder": "Informations about intensity: did you do your full program, did you stop before the end, why did you stop before the end, …", # pylint: disable=line-too-long
"placeholder": "Informations about intensity: why did you do more/less than your program, did you stop before the end, why did you stop before the end, …", # pylint: disable=line-too-long
}
),
}
@ -734,6 +740,7 @@ class SeasonInformationForm(forms.ModelForm):
"number_of_s_and_c_hours_per_week",
"category",
"club",
"informations",
)
widgets = {
"gymnast": forms.HiddenInput(),
@ -754,6 +761,12 @@ class SeasonInformationForm(forms.ModelForm):
),
"category": forms.Select(attrs={"class": "form-control selectpicker"}),
"club": forms.HiddenInput(),
"informations": forms.Textarea(
attrs={
"class": "form-control",
"placeholder": "Informations about intensity: did you do your full program, did you stop before the end, why did you stop before the end, …", # pylint: disable=line-too-long
}
),
}
club_related = forms.CharField(

View File

@ -12,8 +12,6 @@ class Command(BaseCommand):
for intensity in intensity_list:
count += 1
# print(str(intensity.id) + " " + str(intensity))
print(intensity.id)
intensity.time_quality = 1
intensity.save()

View File

@ -0,0 +1,25 @@
# Generated by Django 4.2 on 2024-04-16 08:41
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("followup", "0064_intensity_average_time_by_passe_and_more"),
]
operations = [
migrations.AlterModelOptions(
name="heightweight",
options={
"ordering": ["date"],
"verbose_name": "Height & weight",
"verbose_name_plural": "Heights & weights",
},
),
migrations.AlterModelOptions(
name="wellbeing",
options={"ordering": ["date"]},
),
]

View File

@ -0,0 +1,17 @@
# Generated by Django 4.2 on 2024-04-16 08:47
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("followup", "0065_alter_heightweight_options_alter_wellbeing_options"),
]
operations = [
migrations.RemoveField(
model_name="seasoninformation",
name="category",
),
]

View File

@ -0,0 +1,44 @@
# Generated by Django 4.2 on 2024-04-16 08:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("followup", "0066_remove_seasoninformation_category"),
]
operations = [
migrations.CreateModel(
name="CompetitionCategory",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"informations",
models.TextField(
blank=True,
help_text="Only MarkDown is authorized",
null=True,
verbose_name="Comments",
),
),
("long_label", models.CharField(max_length=100)),
("short_label", models.CharField(max_length=10)),
("age_min", models.PositiveSmallIntegerField(blank=True, null=True)),
("age_max", models.PositiveSmallIntegerField(blank=True, null=True)),
],
options={
"verbose_name": "Competition Category",
"verbose_name_plural": "Competition Categories",
},
),
]

View File

@ -0,0 +1,25 @@
# Generated by Django 4.2 on 2024-04-16 09:17
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("followup", "0067_competitioncategory"),
]
operations = [
migrations.AddField(
model_name="seasoninformation",
name="category",
field=models.ForeignKey(
default=1,
on_delete=django.db.models.deletion.CASCADE,
related_name="season_informations",
to="followup.competitioncategory",
),
preserve_default=False,
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 4.2 on 2024-04-17 06:58
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("followup", "0068_seasoninformation_category"),
]
operations = [
migrations.AddField(
model_name="seasoninformation",
name="informations",
field=models.TextField(
blank=True,
help_text="Only MarkDown is authorized",
null=True,
verbose_name="Comments",
),
),
]

View File

@ -15,10 +15,11 @@ from jarvis.core.global_vars import (
CATEGORY_CHOICES,
AGE_CATOGORY_CHOICES,
NOTE_STATUS_CHOICES,
GENDER_CHOICES,
)
from jarvis.tools.models import Markdownizable, Seasonisable
from jarvis.people.models import Gymnast, GENDER_CHOICES
from jarvis.people.models import Gymnast
from jarvis.planning.models import Event
from jarvis.objective.models import Educative, Skill, Routine
from jarvis.location.models import Club
@ -235,6 +236,9 @@ class WellBeing(Markdownizable, Seasonisable):
Représente l'état psychologique/physique d'un gymnaste
"""
class Meta:
ordering = ["date", ]
gymnast = models.ForeignKey(
Gymnast, on_delete=models.CASCADE, default=None, related_name="wellbeings"
)
@ -367,13 +371,20 @@ class NumberOfRoutineDone(Seasonisable):
class HeightWeight(Seasonisable):
"""
Classe permettant de suivre le poids et la taille d'un gymnaste
Classe permettant de suivre le poids et la taille d'un gymnaste.
Voici les autres formules mathématiques les plus connues, valables pour les adultes :
- La formule de Broca est très simple. Le poids idéal correspond à la différence entre votre taille en cm et 100. Vous mesurez 170 cm et votre poids idéal est de 70 kg.
- La formule de Lorentz tient compte du sexe. Pour une femme, on calcule taille en cm 100 [(taille 150)/2,5]. On divisera par 4 pour un homme. Si vous mesurez 170 cm, le résultat est 62 kg.
- La formule de Creff classe la morphologie en trois catégories, très subjectives : normal, large et gracile. Le poids idéal est augmenté de 10 % pour les larges et réduit de 10 % pour les graciles. Pour une silhouette normale, la formule est taille en cm 100 + (âge/10) X 0,9. Pour une femme dune quarantaine dannées et de 1,70 cm, on obtient 66,6 kg.
- La formule de Monnerot-Dumaine prend en compte lossature en se basant sur la circonférence du poignet. Le calcul : (Taille en cm 100) + (4 x Circonférence du poignet en cm) / 2. Pour notre femme de 170 cm avec un poignet de 16 cm, le résultat est 67 kg.
"""
class Meta:
verbose_name = "Height & weight"
verbose_name_plural = "Heights & weights"
unique_together = ("gymnast", "date")
ordering = ["date",]
gymnast = models.ForeignKey(
Gymnast,
@ -396,6 +407,33 @@ class HeightWeight(Seasonisable):
height = self.height / 100
return self.weight / (height * height)
@property
def bmi_quality(self):
bmi = self.bmi
if self.gymnast.gender == 0:
if bmi < 19:
return 2
elif bmi < 21:
return 1
elif bmi < 23:
return 0
elif bmi < 25:
return 1
else:
return 2
else:
if bmi < 21:
return 2
elif bmi < 23:
return 1
elif bmi < 25:
return 0
elif bmi < 27:
return 1
else:
return 2
def __str__(self):
return f"{self.gymnast} : {self.height}/{self.hips_height} - {self.weight}"
@ -481,136 +519,74 @@ class Intensity(Markdownizable, Seasonisable):
average_time_by_passe = models.DecimalField(max_digits=4, decimal_places=3)
def compute_average_training_quality(self):
"""
Calcul de la qualité d'un entrainement sur base des 4 données pratiques encodées : Temps,
"""Calcul de la qualité d'un entrainement sur base des 4 données pratiques encodées : Temps,
# de passage, # de saut et Difficulté.
Si les 4 données pratiques sont inférieures ou égales aux données théoriques, une moyenne
pondérée (D*4, p*3, S*2 et T) est calculée.
Si une (ou plusieurs) données pratiques sont supérieures aux données théorique... ?
Pour les cas non traités, une moyenne arithmétique est calculée.
TODO:
- trouver un calcul d'efficacité qui tienne compte des statistiques (notamment le temps par
passage)
"""
# Si les 4 données pratiques sont inférieures ou égales aux données théoriques, une moyenne
# pondérée (D*4, p*3, S*2 et T) est calculée.
if (
self.time <= self.theorical_time
and self.number_of_passes <= self.number_of_passes_asked
and self.difficulty <= self.difficulty_asked
and self.quantity_of_skill <= self.quantity_of_skill_asked
):
return (
self.time_quality
+ (self.quantity_of_skill_quality * 2)
+ (self.number_of_passes_quality * 3)
+ (self.difficulty_quality * 4)
) / 10
# if self.difficulty > self.difficulty_asked:
# if (
# self.time <= self.theorical_time
# and self.number_of_passes <= self.number_of_passes_asked
# and self.quantity_of_skill <= self.quantity_of_skill_asked
# ):
# return self.difficulty_quality
if (
self.time <= self.theorical_time
and self.number_of_passes <= self.number_of_passes_asked
):
if (
self.difficulty >= self.difficulty_asked
and self.quantity_of_skill >= self.quantity_of_skill_asked
):
return (
(self.difficulty_quality * 2) + self.quantity_of_skill_quality
) / 3
# Pour les cas non traités, une moyenne arithmétique est calculée.
return (
self.time_quality
+ self.difficulty_quality
+ self.quantity_of_skill_quality
+ self.number_of_passes_quality
) / 4
+ (self.quantity_of_skill_quality * 2)
+ (self.number_of_passes_quality * 3)
+ (self.difficulty_quality * 4)
) / 10
def save(self, *args, **kwargs):
"""Calcule les informations de qualité de l'intensité de entraînement et sauve les informations."""
# self.average_time_by_skill = self.time / self.quantity_of_skill
self.time_quality = round((self.time / self.theorical_time) * 100, 3)
self.difficulty_quality = round(
(self.difficulty / self.difficulty_asked) * 100, 3
)
self.quantity_of_skill_quality = round(
(self.quantity_of_skill / self.quantity_of_skill_asked) * 100, 3
)
self.number_of_passes_quality = round(
(self.number_of_passes / self.number_of_passes_asked) * 100, 3
)
self.average_training_quality = round(
self.compute_average_training_quality(), 3
)
self.average_time_by_passe = round(self.time / self.number_of_passes, 3)
"""Calculate quality metrics for training intensity and save the information."""
def calculate_quality(actual, expected):
"""Helper function to calculate quality percentage."""
if expected > 0:
return round((actual / expected) * 100, 3)
return 0 # Return 0 or some other appropriate value if expected is zero
# Calculate quality metrics
self.time_quality = calculate_quality(self.time, self.theorical_time)
self.difficulty_quality = calculate_quality(self.difficulty, self.difficulty_asked)
self.quantity_of_skill_quality = calculate_quality(self.quantity_of_skill, self.quantity_of_skill_asked)
self.number_of_passes_quality = calculate_quality(self.number_of_passes, self.number_of_passes_asked)
# Calculate average training quality and time per pass
self.average_training_quality = round(self.compute_average_training_quality(), 3)
if self.number_of_passes > 0:
self.average_time_by_passe = round(self.time / self.number_of_passes, 3)
else:
self.average_time_by_passe = 0 # Handle zero passes appropriately even if it should not append.
super().save(*args, **kwargs)
def __str__(self):
return f"{self.gymnast} - {self.date} : {self.time_quality} - {self.difficulty_quality} - {self.quantity_of_skill_quality} - {self.number_of_passes_quality} - {self.average_training_quality} - {self.average_time_by_passe}" # pylint: disable=line-too-long
#
@property
def passes_quality_for_gymnast(self):
"""Calcule la qualité de passage pour un entraînement. On calcule le temps pour un gymnaste
en additionnant le passage théorique optimale d'un passage (90 secondes) et un temps de
fonctionnement (pour monter, descendre, communiquer, ) équivalent racine cubique du nombre
de gymnaste) ; le tout multiplié par le nombre de gymnaste du groupe. Le tout calculé en
seconde puis ramener en minute.
"""Calculate the quality of passes for a training session. This calculates the time for a gymnast
by adding the optimal theoretical time for a pass (90 seconds) and a operational time (for getting on and off, communicating, etc.) (calculated as the cube root of the number of gymnasts), multiplied by the number of gymnasts in the group, and then converted from seconds to minutes.
La qualité de passage représente donc le temps nécessaire pour que tous les gymnastes du
groupe ait fait chacun un passage.
The quality of passes represents the time needed for all gymnasts in the group to each make a pass.
"""
optimal_time_by_gymnast = 90
average_passe_time = (
(optimal_time_by_gymnast + pow(100, 1 / self.number_of_gymnast))
* self.number_of_gymnast
) / 60
if self.number_of_gymnast == 0:
return 0 # Handle case where there are no gymnasts to avoid division by zero
optimal_time_by_gymnast = 90
operational_time = pow(100, 1 / self.number_of_gymnast)
total_time_per_gymnast = optimal_time_by_gymnast + operational_time
total_group_time_seconds = total_time_per_gymnast * self.number_of_gymnast
average_passe_time = total_group_time_seconds / 60
# Calculate the threshold for a 5% increase
threshold_time = average_passe_time * 1.05
# Determine the quality based on the average time per pass
if self.average_time_by_passe <= average_passe_time:
return 1
if self.average_time_by_passe <= (average_passe_time * 1.05):
elif self.average_time_by_passe <= threshold_time:
return 2
if self.average_time_by_passe >= (average_passe_time * 1.05):
else:
return 3
# Theorical statistics
# @property
# def average_time_by_passe_theorical(self):
# return self.theorical_time / self.number_of_passes_asked
# @property
# def average_quantity_of_skill_by_time_theorical(self):
# return self.quantity_of_skill_asked / self.theorical_time
# @property
# def average_time_by_skill_theorical(self):
# return self.theorical_time / self.quantity_of_skill_asked
# @property
# def average_difficulty_by_passe_theorical(self):
# return self.difficulty_asked / self.number_of_passes_asked
# @property
# def average_quantity_of_skill_by_passe_theorical(self):
# return self.quantity_of_skill_asked / self.number_of_passes_asked
# @property
# def average_difficulty_by_skill_theorical(self):
# return self.difficulty_asked / self.quantity_of_skill_asked
# Real statistics
@property
def average_time_by_skill(self):
@ -659,7 +635,22 @@ class Intensity(Markdownizable, Seasonisable):
return self.difficulty_asked / 10
class SeasonInformation(models.Model):
class CompetitionCategory(Markdownizable):
"""Classe représentant les catégories de compétitions"""
class Meta:
verbose_name = "Competition Category"
verbose_name_plural = "Competition Categories"
long_label = models.CharField(max_length=100)
short_label = models.CharField(max_length=10)
age_min = models.PositiveSmallIntegerField(blank=True, null=True)
age_max = models.PositiveSmallIntegerField(blank=True, null=True)
def __str__(self):
return f"{self.short_label}"
class SeasonInformation(Markdownizable):
"""Classe représentant l'intensité d'un entraînement"""
class Meta:
@ -691,9 +682,8 @@ class SeasonInformation(models.Model):
max_digits=3,
decimal_places=1,
)
category = models.PositiveSmallIntegerField(
choices=CATEGORY_CHOICES_ARRAY,
verbose_name="Category",
category = models.ForeignKey(
CompetitionCategory, on_delete=models.CASCADE, related_name="season_informations"
)
club = models.ForeignKey(
Club, null=True, on_delete=models.SET_NULL, related_name="season_informations"

View File

@ -52,13 +52,13 @@
<script type="text/javascript" >
$(document).ready(function() {
var number_of_jump = {{ number_of_jump }};
var score_type = {{ score_type }};
var is_tof_score = {{ score_type }};
$('#jump_score').focus();
function send_score_to_database(score)
{
var jump_value = score / 100;
if(score_type && score.length >= 4) // tof
if(!is_tof_score && score.length >= 4) // tof
var jump_value = jump_value / 10;
$.ajax({
@ -94,7 +94,7 @@
$('#jump_score').keyup(function(){
var score = $('#jump_score').val();
if((score_type && score.length >= 4) || (!score_type && score.length >= 3))
if((!is_tof_score && score.length >= 3) || (is_tof_score && score.length >= 4))
send_score_to_database(score);
});

View File

@ -18,7 +18,7 @@
{% if request.user|has_group:"trainer" %}
{{ form.gymnast }}
{{ form.gymnast_related }}
{% if form.gymnast.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.gymnast.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% else %}
<input type="text" class="form-control" value="{{ request.user.first_name }} {{ request.user.last_name }}" readonly="readonly" />
<input type="hidden" name="gymnast" id="gymnast" value="{{ request.user.gymnast.id }}" />
@ -29,28 +29,28 @@
<label for="id_gymnast" class="col-4 col-sm-3 col-form-label">Date <span class="text-danger"><b>*</b></span></label>
<div class="col-6 col-sm-3 col-md-4 col-lg-4 col-xl-4 {% if form.date.errors %}has-danger{% endif %}">
{{ form.date }}
{% if form.date.errors %}<span class="btn btn-sm btn-danger-outline">{% for error in form.date.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.date.errors %}<span class="btn btn-sm">{% for error in form.date.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row">
<label for="id_chrono_type" class="col-4 col-sm-3 col-form-label">Chrono Type <span class="text-danger"><b>*</b></span></label>
<div class="col-4 col-sm-3 col-md-4 col-lg-4 col-xl-4 {% if form.chrono_type.errors %}has-danger{% endif %}">
{{ form.chrono_type }}
{% if form.chrono_type.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.chrono_type.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.chrono_type.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.chrono_type.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row">
<label for="id_score_type" class="col-4 col-sm-3 col-form-label">Score Type <span class="text-danger"><b>*</b></span></label>
<div class="col-4 col-sm-3 col-md-4 col-lg-4 col-xl-4 {% if form.score_type.errors %}has-danger{% endif %}">
{{ form.score_type }}
{% if form.score_type.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.score_type.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.score_type.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.score_type.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row">
<label for="id_score" class="col-4 col-sm-3 col-form-label">Score <span class="text-danger"><b>*</b></span></label>
<div class="col-3 col-sm-3 col-md-4 col-lg-3 {% if form.score.errors %}has-danger{% endif %}">
{{ form.score }}
{% if form.score.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.score.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.score.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.score.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
{{ form.tof }}

View File

@ -6,32 +6,102 @@
<div class="row">
<div class="col-8">
<h4 class="">
{% if gymnast %}<i><a href="{% url 'gymnast_details_tab' gymnast.id 'scores' %}">{{ gymnast }}</a></i>'s{% endif %} chronos listing
{% if gymnast %}
{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}
<a href="{% url 'gymnast_details_tab' gymnast.id 'scores' %}">
{% endif %}
{{ gymnast }}{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}</a>{% endif %}'s
{% endif %} chronos
</h4>
</div>
<div class="col-1 ml-auto">
<div class="text-right">
<a
href="{% if gymnast %}{% url 'chrono_create_for_gymnast' gymnast.id %}{% else %}{% url 'chrono_create' %}{% endif %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fas fa-plus"></i>
</button>
</a>
<h3 class="mb-0">
<a href="{% if gymnast %}{% url 'chrono_create_for_gymnast' gymnast.id %}{% else %}{% url 'chrono_create' %}{% endif %}">
<i class="fas fa-plus text-warning"></i>
</a>
</h3>
</div>
</div>
</div>
</div>
<div class="card-body vh-100">
<div class="table-responsive">
{% if chrono_list %}
<div class="card-body pt-0 pb-0">
{% if gymnast %}
<div class="row">
<div class="col-md-6">
<table class="table table-striped tablesorter" id="chrono_table">
<thead>
<tr>
<th style="width: 8%">&nbsp;</th>
<th style="width: 12%" class="header text-center">Date</th>
<th style="width: 20%" class="header text-center">Routine</th>
<th style="width: 15%" class="header text-center">Type</th>
<th style="width: 10%" class="header text-center">Score</th>
<th style="width: 10%" class="header text-center">TOF</th>
</tr>
</thead>
<tbody>
{% for chrono in chrono_list %}
<tr role="row" class="{% cycle 'odd' 'even' %}">
<td>
<a href="{% url 'chrono_update' chrono.id %}">
<span class="tim-icons icon-pencil text-warning"></span>
</a>
&nbsp;
<a href="{% url 'jump_chrono_values_create_or_update' chrono.id %}">
<span class="far fa-search-plus text-warning"></span>
</a>
</td>
<td class="text-center">
{% if chrono.details.all %}
<a href="{% url 'jump_chrono_details' chrono.id %}">
{% endif %}
{{ chrono.date | date:"j-n-Y" }}
{% if chrono.details.all %}
</a>
{% endif %}
</td>
<td class="text-center">
{% if chrono.routine %}
{{ chrono.routine.long_label }}
{% else %}
{{ chrono.get_chrono_type_display }}
{% endif %}
</td>
<td class="text-center">{{ chrono.get_score_type_display }}</td>
<td class="text-center">{{ chrono.score }}</td>
<td class="text-center">{{ chrono.tof }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="col-md-6 pl-0 pr-0 pt-3 row">
<div class="col-12">
<canvas id="chart_chrono" class="chartjs" width="100%">
Your browser doesn't support canvas
</canvas>
</div>
<div class="col-12 text-center">
<p>{{ personnal_best_10.date | date:"l j F Y" }} : <b class="text-danger">{{ personnal_best_10.tof }}</b> (ToF) | <b>{{ personnal_best_10.score }}</b> sec</p>
{% if personnal_best_q1r1 %}
<p>{{ personnal_best_q1r1.date | date:"l j F Y" }} : <b class="text-danger">{{ personnal_best_q1r1.tof }}</b> (ToF) | <b>{{ personnal_best_q1r1.score }}</b> sec ({% widthratio personnal_best_q1r1.tof personnal_best_10.score 100 %}%)</p>
{% endif %}
{% if personnal_best_q1r2 %}
<p>{{ personnal_best_q1r2.date | date:"l j F Y" }} : <b class="text-danger">{{ personnal_best_q1r2.tof }}</b> (ToF) | <b>{{ personnal_best_q1r2.score }}</b> sec ({% widthratio personnal_best_q1r2.tof personnal_best_10.score 100 %}%)</p>
{% endif %}
</div>
</div>
</div>
{% else %}
{% if chrono_list %}
<div class="table-responsive pb-0">
<table class="table table-striped tablesorter" id="chrono_table">
<thead>
<tr>
<th style="width: 6%">&nbsp;</th>
<th style="width: 12%" class="header">Date</th>
{% if not gymnast %}
<th style="width: 25%" class="header text-left">Gymnast</th>
{% endif %}
<th style="width: 25%" class="header text-left">Gymnast</th>
<th style="width: 25%" class="header text-left">Routine</th>
<th style="width: 15%" class="header">Type</th>
<th style="width: 10%" class="header text-center">Score</th>
@ -50,14 +120,20 @@
<span class="far fa-search-plus text-warning"></span>
</a>
</td>
<td>{% if chrono.details.all %}<a href="{% url 'jump_chrono_details' chrono.id %}">{% endif %}{{ chrono.date | date:"j-n-Y" }}{% if chrono.details.all %}</a>{% endif %}</td>
{% if not gymnast %}
<td class="text-left">
{% if chrono.gymnast.id in request.session.available_gymnast or request.user.is_superuser %}<a href="{% url 'gymnast_details_tab' chrono.gymnast.id 'scores' %}">{% endif %}
{{ chrono.gymnast }}
<td>
{% if chrono.details.all %}
<a href="{% url 'jump_chrono_details' chrono.id %}">
{% endif %}
{{ chrono.date | date:"j-n-Y" }}
{% if chrono.details.all %}
</a>
</td>
{% endif %}
{% endif %}
</td>
<td class="text-left">
{% if chrono.gymnast.id in request.session.available_gymnast or request.user.is_superuser %}<a href="{% url 'gymnast_details_tab' chrono.gymnast.id 'scores' %}">{% endif %}
{{ chrono.gymnast }}
</a>
</td>
<td class="text-left">
{% if chrono.routine %}
{{ chrono.routine.long_label }}
@ -73,9 +149,10 @@
</tbody>
</table>
{% else %}
<p class="text-muted">There are no chronos corresponding to your criterias.</p>
<p class="text-muted">There are no chronos corresponding to your criterias.</p>
{% endif %}
</div>
{% endif %}
</div>
</div>
{% endblock %}
@ -84,10 +161,10 @@
<script type="text/javascript">
$(document).ready(function () {
$('#chrono_table').tablesorter({
dateFormat : "ddmmyyyy",
headers: {
0: { sorter: false },
},
dateFormat: "uk",
sortList: [[1, 1], [2, 1]]
});
@ -100,5 +177,162 @@
"bInfo": false,
});
});
{% if chrono_list %}
var timeFormat = 'DD-MM-YYYY';
var ctx = document.getElementById('chart_chrono').getContext('2d');
var border_color_pink = 'rgb(255, 99, 132)';
var gradient_stroke_pink = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_pink.addColorStop(1, 'rgba(255, 99, 132, 0.4)');
gradient_stroke_pink.addColorStop(0.75, 'rgba(255, 99, 132, 0.3)');
gradient_stroke_pink.addColorStop(0.5, 'rgba(255, 99, 132, 0.2)');
gradient_stroke_pink.addColorStop(0.25, 'rgba(255, 99, 132, 0)');
var border_color_orange = 'rgb(255, 159, 64)';
var gradient_stroke_orange = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_orange.addColorStop(1, 'rgba(255, 159, 64, 0.4)');
gradient_stroke_orange.addColorStop(0.75, 'rgba(255, 159, 64, 0.3)');
gradient_stroke_orange.addColorStop(0.5, 'rgba(255, 159, 64, 0.2)');
gradient_stroke_orange.addColorStop(0.25, 'rgba(255, 159, 64, 0)');
var border_color_green = 'rgb(75, 192, 192)';
var gradient_stroke_green = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_green.addColorStop(1, 'rgba(75, 192, 192, 0.4)');
gradient_stroke_green.addColorStop(0.75, 'rgba(75, 192, 192, 0.3)');
gradient_stroke_green.addColorStop(0.5, 'rgba(75, 192, 192, 0.2)');
gradient_stroke_green.addColorStop(0.25, 'rgba(75, 192, 192, 0)');
var border_color_blue = 'rgb(54, 162, 235)';
var gradient_stroke_blue = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_blue.addColorStop(1, 'rgba(54, 162, 235, 0.4)');
gradient_stroke_blue.addColorStop(0.75, 'rgba(54, 162, 235, 0.3)');
gradient_stroke_blue.addColorStop(0.5, 'rgba(54, 162, 235, 0.2)');
gradient_stroke_blue.addColorStop(0.25, 'rgba(54, 162, 235, 0)');
var border_color_yellow = 'rgb(255, 205, 86)';
var gradient_stroke_yellow = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_yellow.addColorStop(1, 'rgba(255, 205, 86, 0.4)');
gradient_stroke_yellow.addColorStop(0.75, 'rgba(255, 205, 86, 0.3)');
gradient_stroke_yellow.addColorStop(0.5, 'rgba(255, 205, 86, 0.2)');
gradient_stroke_yellow.addColorStop(0.25, 'rgba(255, 205, 86, 0)');
var straightjump_values = [
{% for chrono in chrono_10c %}
{
x: '{{ chrono.date | date:"d-m-Y" }}',
y: '{{ chrono.score_avg | floatformat:3 }}'
},
{% endfor %}
];
var compulsory_routine_values = [
{% for chrono in chrono_r1 %}
{
x: '{{ chrono.date | date:"d-m-Y" }}',
y: '{{ chrono.score_avg | floatformat:3 }}'
},
{% endfor %}
];
var volontary_routine_values = [
{% for chrono in chrono_r2 %}
{
x: '{{ chrono.date | date:"d-m-Y" }}',
y: '{{ chrono.score_avg | floatformat:3 }}'
},
{% endfor %}
];
var final_routine_values = [
{% for chrono in chrono_rf %}
{
x: '{{ chrono.date | date:"d-m-Y" }}',
y: '{{ chrono.score_avg | floatformat:3 }}'
},
{% endfor %}
];
var chrono_values = {
datasets: [
{% if chrono_10c %}
{
label: '10 |',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_pink,
borderColor: border_color_pink,
pointBackgroundColor: border_color_pink,
fill: true,
data: straightjump_values,
},
{% endif %}
{% if chrono_r1 %}
{
label: 'Q1R1',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_orange,
borderColor: border_color_orange,
pointBackgroundColor: border_color_orange,
fill: true,
data: compulsory_routine_values,
},
{% endif %}
{% if chrono_r2 %}
{
label: 'Q1R2',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_green,
borderColor: border_color_green,
pointBackgroundColor: border_color_green,
fill: true,
data: volontary_routine_values,
},
{% endif %}
{% if chrono_rf %}
{
label: 'Q2R1',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_blue,
borderColor: border_color_blue,
pointBackgroundColor: border_color_blue,
fill: true,
data: final_routine_values,
},
{% endif %}
]
}
new Chart(ctx, {
type: 'line',
data: chrono_values,
options: {
scales: {
x: {
type: 'time',
display: true,
scaleLabel: {
display: true,
labelString: 'Date',
ticks: {
autoSkip: true,
source: 'data',
},
},
time: {
parser: timeFormat,
tooltipFormat: 'LL',
round: 'day',
},
},
},
plugins: {
legend: {
display: true,
position: 'bottom',
}
}
},
});
{% endif %}
</script>
{% endblock %}

View File

@ -27,7 +27,7 @@
{% if request.user|has_group:"trainer" %}
{{ form.gymnast }}
{{ form.gymnast_related }}
{% if form.gymnast.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.gymnast.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% else %}
<input type="text" class="form-control" value="{{ request.user.first_name }} {{ request.user.last_name }}" readonly="readonly" />
<input type="hidden" name="gymnast" id="gymnast" value="{{ request.user.gymnast.id }}" />
@ -40,7 +40,7 @@
class="text-danger"><b>*</b></span></label>
<div class="col-6 col-sm-3 col-md-4 col-lg-4 col-xl-3 {% if form.date.errors %}has-danger{% endif %}">
{{ form.date }}
{% if form.date.errors %}<span class="btn btn-sm btn-danger-outline">{% for error in form.date.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.date.errors %}<span class="btn btn-sm">{% for error in form.date.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
@ -49,7 +49,7 @@
class="text-danger"><b>*</b></span></label>
<div class="col-4 col-sm-3 col-md-3 col-lg-3 {% if form.height.errors %}has-danger{% endif %}">
{{ form.height }}
{% if form.height.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.height.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.height.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.height.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
@ -57,7 +57,7 @@
<div
class="col-4 col-sm-3 col-md-3 col-lg-3 {% if form.hips_height.errors %}has-danger{% endif %}">
{{ form.hips_height }}
{% if form.hips_height.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.hips_height.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.hips_height.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.hips_height.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
@ -65,7 +65,7 @@
class="text-danger"><b>*</b></span></label>
<div class="col-4 col-sm-3 col-md-3 col-lg-3 {% if form.weight.errors %}has-danger{% endif %}">
{{ form.weight }}
{% if form.weight.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.weight.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.weight.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.weight.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group text-center">

View File

@ -1,5 +1,6 @@
{% extends "listing.html" %}
{% load has_group %}
{% load static %}
{% block datacontent %}
<div class="row justify-content-center">
@ -7,88 +8,156 @@
<div class="card">
<div class="card-header row">
<div class="col-10 pr-0">
<h4 class="">{% if gymnast %}<a href="{% url 'gymnast_details_tab' gymnast.id 'physiological' %}"><i>{{ gymnast }}</i></a>'s{% endif %} Height/Weight listing </h4>
<h4 class="">
{% if gymnast %}
{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}
<a href="{% url 'gymnast_details_tab' gymnast.id 'physiological' %}">
{% endif %}
{{ gymnast }}
{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}
</a>
{% endif %}'s
{% endif %} Height/Weight
</h4>
</div>
<div class="col-2 ml-auto pl-0">
<div class="text-right">
{% if request.user|has_group:"trainer" %}
<a href="{% if gymnast %}{% url 'heightweight_create_for_gymnast' gymnast.id %}{% else %}{% url 'heightweight_create' %}{% endif %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fas fa-plus"></i>
</button>
</a>
<h3 class="mb-0">
<a href="{% if gymnast %}{% url 'heightweight_create_for_gymnast' gymnast.id %}{% else %}{% url 'height_weight_create' %}{% endif %}">
<i class="fas fa-plus text-warning"></i>
</a>
</h3>
{% endif %}
</div>
</div>
</div>
<div class="card-body pt-1">
{% if heightweight_list %}
<table class="table tablesorter table-striped mb-0" data-sort="table" id="heightweight_table">
<thead>
<tr>
<th></th>
<th class="header text-left">Date</th>
{% if not gymnast %}
<th class="header text-left">Gymnast</th>
{% endif %}
<th class="header text-center">Height</th>
<th class="header text-center">Hips height</th>
<th class="header text-center">Weight</th>
<th class="header text-center">BMI</th>
</tr>
</thead>
<tbody>
{% for heightweight in heightweight_list %}
<tr>
<td>
<a href="{% url 'heightweight_update' heightweight.id %}">
<span class="tim-icons icon-pencil text-warning"></span>
</a>
</td>
<td class="text-left">{{ heightweight.date | date:"j-n-Y" }}</td>
{% if not gymnast %}
<td class="text-left">{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}<a href="{% url 'gymnast_details' heightweight.gymnast.id %}">{% endif %}{{ heightweight.gymnast }}</a></td>
{% endif %}
<td class="text-center">{{ heightweight.height }}</td>
<td class="text-center">{% if heightweight.hips_height == None %}-{% else %}{{ heightweight.hips_height }}{% endif %}</td>
<td class="text-center">{{ heightweight.weight }}</td>
<td class="text-center">
{% if gymnast %}
{% if gymnast.gender == 0 %}
{% if heightweight.bmi < 19 %}
<span class="text-danger"><b>{{ heightweight.bmi | floatformat:2 }}</b></span>
{% elif heightweight.bmi < 21 %}
<span class="text-warning"><b>{{ heightweight.bmi | floatformat:2 }}</b></span>
{% elif heightweight.bmi < 23 %}
<span class="text-success"><b>{{ heightweight.bmi | floatformat:2 }}</b></span>
{% elif heightweight.bmi < 25 %}
<span class="text-warning"><b>{{ heightweight.bmi | floatformat:2 }}</b></span>
{% else %}
<span class="text-danger"><b>{{ heightweight.bmi | floatformat:2 }}</b></span>
{% endif %}
<div class="card-body pt-0">
{% if gymnast %}
<div class="row">
<div class="col-md-6">
<table class="table tablesorter table-striped mb-0" data-sort="table" id="height_weight_table">
<thead>
<tr>
<th></th>
<th class="header text-left">Date</th>
<th class="header text-center">Height</th>
<th class="header text-center">Hips height</th>
<th class="header text-center">Weight</th>
<th class="header text-center">BMI</th>
</tr>
</thead>
<tbody>
{% for height_weight in height_weight_list %}
<tr>
<td>
<a href="{% url 'heightweight_update' height_weight.id %}">
<span class="tim-icons icon-pencil text-warning"></span>
</a>
</td>
<td class="text-left">{{ height_weight.date | date:"j-n-Y" }}</td>
<td class="text-center">{{ height_weight.height }}</td>
<td class="text-center">
{% if height_weight.hips_height == None %}
-
{% else %}
{{ height_weight.hips_height }}
{% endif %}
</td>
<td class="text-center">{{ height_weight.weight }}</td>
<td class="text-center">
{% if gymnast %}
{% if height_weight.bmi_quality == 2 %}
<span class="text-danger">
{% elif height_weight.bmi_quality == 1 %}
<span class="text-warning">
{% elif height_weight.bmi_quality == 0 %}
<span class="text-success">
{% endif %}
{% endif %}
<b>{{ height_weight.bmi | floatformat:2 }}</b>
{% if gymnast %}
</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="col-md-6 pl-0 pr-0 pt-3">
<canvas id="chart_height_weight" class="chartjs" width="100%">
Your browser doesn't support canvas
</canvas>
</div>
</div>
{% else %}
{% if height_weight_list %}
<table class="table tablesorter table-striped mb-0" data-sort="table" id="height_weight_table">
<thead>
<tr>
<th></th>
<th class="header text-left">Date</th>
{% if not gymnast %}
<th class="header text-left">Gymnast</th>
{% endif %}
<th class="header text-center">Height</th>
<th class="header text-center">Hips height</th>
<th class="header text-center">Weight</th>
<th class="header text-center">BMI</th>
</tr>
</thead>
<tbody>
{% for height_weight in height_weight_list %}
<tr>
<td>
<a href="{% url 'height_weight_update' height_weight.id %}">
<span class="tim-icons icon-pencil text-warning"></span>
</a>
</td>
<td class="text-left">{{ height_weight.date | date:"j-n-Y" }}</td>
{% if not gymnast %}
<td class="text-left">
{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}
<a href="{% url 'gymnast_details' height_weight.gymnast.id %}">
{% endif %}
{{ height_weight.gymnast }}
{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}
</a>
{% endif %}
</td>
{% endif %}
<td class="text-center">{{ height_weight.height }}</td>
<td class="text-center">
{% if height_weight.hips_height == None %}
-
{% else %}
{% if heightweight.bmi < 21 %}
<span class="text-danger"><b>{{ heightweight.bmi | floatformat:2 }}</b></span>
{% elif heightweight.bmi < 23 %}
<span class="text-warning"><b>{{ heightweight.bmi | floatformat:2 }}</b></span>
{% elif heightweight.bmi < 25 %}
<span class="text-success"><b>{{ heightweight.bmi | floatformat:2 }}</b></span>
{% elif heightweight.bmi < 27 %}
<span class="text-warning"><b>{{ heightweight.bmi | floatformat:2 }}</b></span>
{% else %}
<span class="text-danger"><b>{{ heightweight.bmi | floatformat:2 }}</b></span>
{{ height_weight.hips_height }}
{% endif %}
</td>
<td class="text-center">{{ height_weight.weight }}</td>
<td class="text-center">
{% if gymnast %}
{% if height_weight.bmi_quality == 2 %}
<span class="text-danger">
{% elif height_weight.bmi_quality == 1 %}
<span class="text-warning">
{% elif height_weight.bmi_quality == 0 %}
<span class="text-success">
{% endif %}
{% endif %}
{% else %}
<b>{{ heightweight.bmi | floatformat:2 }}</b>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p class="text-muted">There are no scores corresponding to your criterias</p>
<b>{{ height_weight.bmi | floatformat:2 }}</b>
{% if gymnast %}
</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p class="text-muted">There are no scores corresponding to your criterias</p>
{% endif %}
{% endif %}
</div>
</div>
@ -97,17 +166,18 @@
{% endblock %}
{% block footerscript %}
<script src="{% static "js/template_users/chart_gradient_color.js" %}"></script>
<script type="text/javascript">
$(document).ready(function () {
$('[data-sort="table"]').tablesorter({
headers: {
0: { sorter: false },
},
dateFormat: "uk",
dateFormat : "ddmmyyyy",
sortList: [[1, 1]]
});
$('#heightweight_table').DataTable({
$('#height_weight_table').DataTable({
scrollY: '50vh',
scrollCollapse: true,
paging: false,
@ -116,5 +186,125 @@
"bInfo" : false,
});
});
{% if height_weight_list %}
var timeFormat = 'DD-M-YYYY';
var ctx = document.getElementById("chart_height_weight").getContext("2d");
var border_color_pink = 'rgb(255, 99, 132)';
var gradient_stroke_pink = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_pink.addColorStop(1, 'rgba(255, 99, 132, 0.4)');
gradient_stroke_pink.addColorStop(0.75, 'rgba(255, 99, 132, 0.3)');
gradient_stroke_pink.addColorStop(0.5, 'rgba(255, 99, 132, 0.2)');
gradient_stroke_pink.addColorStop(0.25, 'rgba(255, 99, 132, 0)');
var border_color_orange = 'rgb(255, 159, 64)';
var gradient_stroke_orange = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_orange.addColorStop(1, 'rgba(255, 159, 64, 0.4)');
gradient_stroke_orange.addColorStop(0.75, 'rgba(255, 159, 64, 0.3)');
gradient_stroke_orange.addColorStop(0.5, 'rgba(255, 159, 64, 0.2)');
gradient_stroke_orange.addColorStop(0.25, 'rgba(255, 159, 64, 0)');
var border_color_green = 'rgb(75, 192, 192)';
var gradient_stroke_green = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_green.addColorStop(1, 'rgba(75, 192, 192, 0.4)');
gradient_stroke_green.addColorStop(0.75, 'rgba(75, 192, 192, 0.3)');
gradient_stroke_green.addColorStop(0.5, 'rgba(75, 192, 192, 0.2)');
gradient_stroke_green.addColorStop(0.25, 'rgba(75, 192, 192, 0)');
var height_values = [
{% for height_weight in height_weight_list %}
{
x: '{{ height_weight.date | date:"d-m-Y" }}',
y: '{{ height_weight.weight }}'
},
{% endfor %}
]
var weight_values = [
{% for height_weight in height_weight_list %}
{
x: '{{ height_weight.date | date:"d-m-Y" }}',
y: '{{ height_weight.height | add:"-100" }}'
},
{% endfor %}
]
var bmi_value = [
{% for height_weight in height_weight_list %}
{
x: '{{ height_weight.date | date:"d-m-Y" }}',
y: '{{ height_weight.bmi }}'
},
{% endfor %}
]
var height_weight_data = {
datasets: [
{
label: 'Weight',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_pink,
borderColor: border_color_pink,
pointBackgroundColor: border_color_pink,
fill: true,
data: height_values,
hidden: true,
},
{
label: 'Height',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_orange,
borderColor: border_color_orange,
pointBackgroundColor: border_color_orange,
fill: true,
data: weight_values,
hidden: true,
},
{
label: 'BMI',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_green,
borderColor: border_color_green,
pointBackgroundColor: border_color_green,
fill: true,
data: bmi_value,
},
],
};
new Chart(ctx, {
responsive: true,
type: 'line',
data: height_weight_data,
options: {
scales: {
x: {
type: 'time',
display: true,
scaleLabel: {
display: true,
labelString: 'Date',
ticks: {
autoSkip: true,
source: 'data',
},
},
time: {
parser: timeFormat,
tooltipFormat: 'LL',
round: 'day',
},
},
},
plugins: {
legend: {
display: true,
position: 'bottom',
}
}
},
});
{% endif %}
</script>
{% endblock %}

View File

@ -18,7 +18,7 @@
{% if request.user|has_group:"trainer" %}
{{ form.gymnast }}
{{ form.gymnast_related }}
{% if form.gymnast.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.gymnast.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% else %}
<input type="text" class="form-control" value="{{ request.user.first_name }} {{ request.user.last_name }}" readonly="readonly" />
<input type="hidden" name="gymnast" id="gymnast" value="{{ request.user.gymnast.id }}" />
@ -29,7 +29,7 @@
<label for="id_date" class="col-4 col-sm-3 col-form-label">{{ form.date.label }} <span class="text-danger"><b>*</b></span></label>
<div class="col-4 col-sm-3 col-md-4 col-lg-4 col-xl-4 {% if form.date.errors %}has-danger{% endif %}">
{{ form.date }}
{% if form.date.errors %}<span class="btn btn-sm btn-danger-outline">{% for error in form.date.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.date.errors %}<span class="btn btn-sm">{% for error in form.date.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
@ -37,42 +37,42 @@
<div class="col-8 col-sm-8 col-md-6 col-lg-6 col-xl-6 {% if form.skill.errors %}has-danger{% endif %}">
{{ form.skill }}
{{ form.skill_related }}
{% if form.skill.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.skill.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.skill.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.skill.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_mechanism" class="col-4 col-sm-3 col-form-label">{{ form.mechanism.label }} <span class="text-danger"><b>*</b></span></label>
<div class="col-4 col-sm-3 col-md-4 col-lg-4 col-xl-4 {% if form.mechanism.errors %}has-danger{% endif %}">
{{ form.mechanism }}
{% if form.mechanism.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.mechanism.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.mechanism.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.mechanism.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_injury_type" class="col-4 col-sm-3 col-form-label">{{ form.injury_type.label }}<span class="text-danger"><b>*</b></span></label>
<div class="col-8 col-sm-6 col-md-8 col-lg-6 col-xl-8 {% if form.injury_type.errors %}has-danger{% endif %}">
{{ form.injury_type }}
{% if form.injury_type.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.injury_type.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.injury_type.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.injury_type.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_location" class="col-4 col-sm-3 col-form-label">{{ form.location.label }}<span class="text-danger"><b>*</b></span></label>
<div class="col-8 col-sm-5 col-md-6 col-lg-6 col-xl-6 {% if form.location.errors %}has-danger{% endif %}">
{{ form.location }}
{% if form.location.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.location.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.location.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.location.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_body_side" class="col-4 col-sm-3 col-form-label">{{ form.body_side.label }}<span class="text-danger"><b>*</b></span></label>
<div class="col-5 col-sm-3 col-md-4 col-lg-4 col-xl-4 {% if form.body_side.errors %}has-danger{% endif %}">
{{ form.body_side }}
{% if form.body_side.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.body_side.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.body_side.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.body_side.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_nb_week_off" class="col-4 col-sm-3 col-form-label"># Week off</label>
<div class="col-3 col-sm-2 col-md-4 col-lg-2 col-xl-3 {% if form.nb_week_off.errors %}has-danger{% endif %}">
{{ form.nb_week_off }}
{% if form.nb_week_off.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.nb_week_off.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.nb_week_off.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.nb_week_off.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">

View File

@ -21,7 +21,7 @@
<div class="card-footer row">
<div class="col-6">
<a href="{% url 'injuries_list' %}">
<a href="{% url 'injury_list' %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="tim-icons icon-double-left"></i>
</button>

View File

@ -4,38 +4,43 @@
<div class="card mb-0">
<div class="card-header">
<div class="row">
<div class="col-md-4">
<h4 class=""> Injuries Listing</h4>
<div class="col-8">
<h4 class="">
{% if gymnast %}
{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}<a href="{% url 'gymnast_details_tab' gymnast.id 'physiological' %}">{% endif %}{{ gymnast }}{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}</a>{% endif %}'s i{% else %}I{% endif %}njuries
</h4>
</div>
<div class="col-1 ml-auto">
<div class="col-4 ml-auto">
<div class="text-right">
<a href="{% url 'injury_create' %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fas fa-plus"></i>
</button>
</a>
<h3 class="mb-0">
<a href="{% url 'injury_create' %}">
<i class="fas fa-plus text-warning"></i>
</a>
</h3>
</div>
</div>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
{% if injuries_list %}
<div class="card-body pt-0 pb-0">
<div class="table-responsive pb-0">
{% if injury_list %}
<table class="table tablesorter table-striped" data-sort="table" id="injury_table">
<thead class="text-primary">
<tr>
<th style="width: 3%"></th>
<th class="header text-left" style="width: 8%">Date</th>
<th class="header text-left" style="width: 20%">Gymnast</th>
{% if not gymnast %}
<th class="header text-left" style="width: 20%">Gymnast</th>
{% endif %}
<th class="header text-left" style="width: 9%">Mechanism</th>
<th class="header text-left" style="width: 20%">Location</th>
<th class="header text-left" style="width: 8%">Side</th>
<th style="width: 20%">Skill</th>
<th class="header text-left" style="width: 16%">Side</th>
<th style="width: 12%">Skill</th>
<th style="width: 8%"># Week off</th>
</tr>
</thead>
<tbody>
{% for injury in injuries_list %}
{% for injury in injury_list %}
<tr role="row" class="{% cycle 'odd' 'even' %}">
<td>
<a href="{% url 'injury_update' injury.id %}">
@ -43,13 +48,23 @@
</a>
</td>
<td class="text-left"><a href="{% url 'injury_details' injury.id %}">{{ injury.date | date:"j-n-Y" }}</a></td>
<td class="text-left">{% if injury.gymnast.id in request.session.available_gymnast or request.user.is_superuser %}<a href="{% url 'gymnast_details_tab' injury.gymnast.id 'physiological' %}">{% endif %}{{ injury.gymnast }}</a></td>
{% if not gymnast %}
<td class="text-left">
{% if injury.gymnast.id in request.session.available_gymnast or request.user.is_superuser %}
<a href="{% url 'gymnast_details_tab' injury.gymnast.id 'physiological' %}">
{% endif %}
{{ injury.gymnast }}
{% if injury.gymnast.id in request.session.available_gymnast or request.user.is_superuser %}
</a>
{% endif %}
</td>
{% endif %}
<td class="text-left">{{ injury.get_mechanism_display }}</td>
<td class="text-left">{{ injury.get_location_display }}</td>
<td class="text-left">{{ injury.get_body_side_display }}</td>
<td class="text-left">
{% if injury.skill %}
<a href="{% url 'skill_details' injury.skill.id %}">{{ injury.skill }}</a>
<a href="{% url 'skill_details' injury.skill.id %}">{{ injury.skill.notation }}</a>
{% else %}
-
{% endif %}
@ -66,7 +81,7 @@
</tbody>
</table>
{% else %}
<p class="muted-text">There are no injury corresponding to your criterias.</p>
<p class="text-muted">There are no injury corresponding to your criterias.</p>
{% endif %}
</div>
</div>
@ -80,12 +95,12 @@
headers: {
0: { sorter: false }, // disable first column
},
dateFormat: "uk",
dateFormat : "ddmmyyyy",
sortList: [[1, 1]]
});
$('#injury_table').DataTable({
scrollY: '50vh',
// scrollY: '50vh',
paging: false,
searching: false,
ordering: false,

View File

@ -15,85 +15,89 @@
method="post" class="form-horizontal" id="formulaire" name="formulaire">
{% csrf_token %}
<div class="form-group row ">
<label for="id_date" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-2 col-form-label pr-0">Gymnast <span class="text-danger"><b>*</b></span></label>
<label for="id_date" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-3 col-form-label pr-0">Gymnast <span class="text-danger"><b>*</b></span></label>
<div class="col-8 col-sm-9 col-md-9 col-lg-9 col-lg-8 col-xl-8 {% if form.gymnast.errors %}has-danger{% endif %}">
{{ form.gymnast }}
{{ form.gymnast_related }}
{% if form.gymnast.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.gymnast.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_date" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-2 col-form-label pr-0">Date <span class="text-danger"><b>*</b></span></label>
<label for="id_date" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-3 col-form-label pr-0">Date <span class="text-danger"><b>*</b></span></label>
<div class="col-5 col-sm-3 col-md-4 col-lg-4 col-xl-3 {% if form.date.errors %}has-danger{% endif %}">
{{ form.date }}
{% if form.date.errors %}<span class="btn btn-sm btn-danger-outline">{% for error in form.date.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.date.errors %}<span class="btn btn-sm">{% for error in form.date.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_time" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-2 col-form-label pr-0">Time <span class="text-danger"><b>*</b></span></label>
<label for="id_time" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-3 col-form-label pr-0">Time <span class="text-danger"><b>*</b></span></label>
<div class="col-5 col-sm-2 col-md-3 col-lg-3 {% if form.time.errors %}has-danger{% endif %}">
{{ form.time }}
{% if form.time.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.time.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.time.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.time.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
<label for="id_theorical_time" class="col-4 col-sm-3 col-md-3 col-lg-3 col-xl-3 col-form-label pl-0 pr-0">Theorical time <span class="text-danger"><b>*</b></span></label>
<div class="col-5 col-sm-2 col-md-3 col-lg-3 {% if form.theorical_time.errors %}has-danger{% endif %}">
{{ form.theorical_time }}
{% if form.theorical_time.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.theorical_time.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.theorical_time.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.theorical_time.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_difficulty" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-2 col-form-label pr-0">Difficulty <span class="text-danger"><b>*</b></span></label>
<label for="id_difficulty" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-3 col-form-label pr-0">Difficulty <span class="text-danger"><b>*</b></span></label>
<div class="col-5 col-sm-2 col-md-3 col-lg-3 {% if form.difficulty.errors %}has-danger{% endif %}">
{{ form.difficulty }}
{% if form.difficulty.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.difficulty.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.difficulty.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.difficulty.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
<label for="id_difficulty_asked" class="col-4 col-sm-3 col-md-3 col-lg-3 col-xl-3 col-form-label pl-0 pr-0">Difficulty asked <span class="text-danger"><b>*</b></span></label>
<div class="col-5 col-sm-2 col-md-3 col-lg-3 {% if form.difficulty_asked.errors %}has-danger{% endif %}">
{{ form.difficulty_asked }}
{% if form.difficulty_asked.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.difficulty_asked.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.difficulty_asked.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.difficulty_asked.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_quantity_of_skill" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-2 col-form-label pr-0"># skill <span class="text-danger"><b>*</b></span></label>
<label for="id_quantity_of_skill" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-3 col-form-label pr-0"># skill <span class="text-danger"><b>*</b></span></label>
<div class="col-5 col-sm-2 col-md-3 col-lg-3 {% if form.quantity_of_skill.errors %}has-danger{% endif %}">
{{ form.quantity_of_skill }}
{% if form.quantity_of_skill.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.quantity_of_skill.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.quantity_of_skill.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.quantity_of_skill.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
<label for="id_quantity_of_skill_asked" class="col-4 col-sm-3 col-md-3 col-lg-3 col-xl-3 col-form-label pl-0 pr-0"># skill asked <span class="text-danger"><b>*</b></span></label>
<div class="col-5 col-sm-2 col-md-3 col-lg-3 {% if form.quantity_of_skill_asked.errors %}has-danger{% endif %}">
{{ form.quantity_of_skill_asked }}
{% if form.quantity_of_skill_asked.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.quantity_of_skill_asked.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.quantity_of_skill_asked.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.quantity_of_skill_asked.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_number_of_passes" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-2 col-form-label pr-0"># passes <span class="text-danger"><b>*</b></span></label>
<label for="id_number_of_passes" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-3 col-form-label pr-0"># passes <span class="text-danger"><b>*</b></span></label>
<div class="col-5 col-sm-2 col-md-3 col-lg-3 {% if form.number_of_passes.errors %}has-danger{% endif %}">
{{ form.number_of_passes }}
{% if form.number_of_passes.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.number_of_passes.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.number_of_passes.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.number_of_passes.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
<label for="id_number_of_passes_asked" class="col-4 col-sm-3 col-md-3 col-lg-3 col-xl-3 col-form-label pl-0 pr-0"># passes asked <span class="text-danger"><b>*</b></span></label>
<div class="col-5 col-sm-2 col-md-3 col-lg-3 {% if form.number_of_passes_asked.errors %}has-danger{% endif %}">
{{ form.number_of_passes_asked }}
{% if form.number_of_passes_asked.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.number_of_passes_asked.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.number_of_passes_asked.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.number_of_passes_asked.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_number_of_gymnast" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-2 col-form-label pr-0"># gymnast <span class="text-danger"><b>*</b></span></label>
<label for="id_number_of_gymnast" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-3 col-form-label pr-0"># gymnast <span class="text-danger"><b>*</b></span></label>
<div class="col-5 col-sm-2 col-md-3 col-lg-3 {% if form.number_of_gymnast.errors %}has-danger{% endif %}">
{{ form.number_of_gymnast }}
{% if form.number_of_gymnast.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.number_of_gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.number_of_gymnast.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.number_of_gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group text-center" id="informations_needed">
<p class="text-danger">Details required because at least one quality is above/under the limits.</p>
</div>
<div class="form-group row ">
<label for="id_information" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Informations</label>
<label for="id_information" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-3 col-form-label">Informations <span id="informations_star" class="text-danger"><b>*</b></span></label>
</div>
<div class="form-group row">
<div class="col-12 {% if form.id_informations.errors %}has-danger{% endif %}">
@ -101,7 +105,7 @@
</div>
</div>
<div class="form-group text-center">
<div class="form-group text-center" id="div_submit">
<input type="submit" value="{% if intensity_id %}Update{% else %}Add{% endif %}"
class="btn btn-warning" />
</div>
@ -115,53 +119,124 @@
{% block footerscript %}
<script type="text/javascript">
$(function () {
$('#informations_star').hide();
$("#informations_needed").hide();
blackDashboard.initDateTimePicker();
});
const csrf_token = "{{ csrf_token|escapejs }}";
const gymnast_lookup = "{% url 'gymnast_lookup' %}";
function is_lower_than(number, limit) {
if(number < limit)
return true;
$('#id_club_related').autocomplete({
source: function(request, response) {
$.ajax({
url: club_lookup,
method: "POST",
data: {
pattern: $('#id_club_related').val(),
csrfmiddlewaretoken: csrf_token
},
dataType: "json",
success: function(data) {
if(data.length != 0) {
response($.map(data, function(item) {
return {
label: item.Name,
value: item.Name,
clubid: item.ID
}
}))
} else {
response([{ label: 'No result found.', value: '' }]);
};
},
return false;
}
error: function (exception) {
console.log(exception);
}
});
},
minLength: 3,
select: function (event, ui) {
$($(this).data('ref')).val(ui.item.clubid);
},
{% if request.session.template == 0 %}
classes: {
"ui-widget-content": "custom_autocomplete_ul",
"ui-autocomplete": "custom_autocomplete_ul",
"ui-menu-item-wrapper": "custom_autocomplete_li",
"ui-menu-item": "custom_autocomplete_li",
},
{% endif %}
function is_greater_than(number, limit) {
if(number >= limit)
return true;
return false;
}
function is_informations_needed() {
var time_quality = $('#id_theorical_time').val() / $('#id_time').val();
var diff_quality = $('#id_difficulty_asked').val() / $('#id_difficulty').val();
var skill_quality = $('#id_quantity_of_skill_asked').val() / $('#id_quantity_of_skils').val();
var passe_quality = $('#id_number_of_passes_asked').val() / $('#id_number_of_passes').val();
var limit = 0.7;
var test = is_lower_than(time_quality, limit);
test = test || is_lower_than(diff_quality, limit);
test = test || is_lower_than(skill_quality, limit);
test = test || is_lower_than(passe_quality, limit);
var limit = 1.1;
test = test || is_greater_than(time_quality, limit);
test = test || is_greater_than(diff_quality, limit);
test = test || is_greater_than(skill_quality, limit);
test = test || is_greater_than(passe_quality, limit);
var average_quality = (time_quality + (skill_quality * 2) + (passe_quality * 3) + (diff_quality * 4)) / 10;
test = test || is_lower_than(average_quality, 0.85);
test = test || is_greater_than(average_quality, 1.05);
return test
}
function is_information_field_too_short() {
information_length = $('#id_informations').val().length
if(isNaN(information_length) || information_length < 15)
return true;
else
return false;
};
$('#id_time, #id_theorical_time, #id_difficulty, #id_difficulty_asked, #id_quantity_of_skill, #id_quantity_of_skill_asked, #id_number_of_passes, #id_number_of_passes_asked').keyup(function(){
if(is_informations_needed() && is_information_field_too_short()) {
$("#informations_needed").show();
$('#informations_star').show();
$("#div_submit").hide();
} else {
$("#informations_needed").hide();
$('#informations_star').hide();
$("#div_submit").show();
}
});
$('#id_informations').on('keyup', function(){
if(is_informations_needed() && is_information_field_too_short()) {
$("#informations_needed").show();
$("#div_submit").hide();
} else {
$("#informations_needed").hide();
$("#div_submit").show();
}
});
const csrf_token = "{{ csrf_token|escapejs }}";
const gymnast_lookup = "{% url 'gymnast_lookup' %}";
$('#id_club_related').autocomplete({
source: function(request, response) {
$.ajax({
url: club_lookup,
method: "POST",
data: {
pattern: $('#id_club_related').val(),
csrfmiddlewaretoken: csrf_token
},
dataType: "json",
success: function(data) {
if(data.length != 0) {
response($.map(data, function(item) {
return {
label: item.Name,
value: item.Name,
clubid: item.ID
}
}))
} else {
response([{ label: 'No result found.', value: '' }]);
};
},
error: function (exception) {
console.log(exception);
}
});
},
minLength: 3,
select: function (event, ui) {
$($(this).data('ref')).val(ui.item.clubid);
},
{% if request.session.template == 0 %}
classes: {
"ui-widget-content": "custom_autocomplete_ul",
"ui-autocomplete": "custom_autocomplete_ul",
"ui-menu-item-wrapper": "custom_autocomplete_li",
"ui-menu-item": "custom_autocomplete_li",
},
{% endif %}
});
});
</script>
<script src="{% static "js/template_users/datepicker_maxdate_today.js" %}"></script>

View File

@ -18,13 +18,14 @@
<div class="col-sm-2 d-none d-sm-block"></div>
<div class="col-4 col-sm-3 pr-0">Time</div>
<div class="col-2 text-right pl-0">
{% if intensity.time_quality <= 85.0 %}
<span class="text-danger">{{ intensity.time_quality | floatformat:1 }}%</span>
{% elif intensity.time_quality <= 95.0 %}
<span class="text-warning">{{ intensity.time_quality | floatformat:1 }}%</span>
{% else %}
<span class="text-success">{{ intensity.time_quality | floatformat:1 }}%</span>
{% endif %}
{% if intensity.time_quality <= 85.0 %}
<span class="text-danger">
{% elif intensity.time_quality <= 95.0 %}
<span class="text-warning">
{% else %}
<span class="text-success">
{% endif %}
{{ intensity.time_quality | floatformat:1 }}%</span>
</div>
@ -33,13 +34,14 @@
<div class="col-sm-2 d-none d-sm-block"></div>
<div class="col-4 col-sm-3 pr-0">Diff.</div>
<div class="col-2 text-right pl-0">
{% if intensity.difficulty_quality <= 85.0 %}
<span class="text-danger">{{ intensity.difficulty_quality | floatformat:1 }}%</span>
{% elif intensity.difficulty_quality <= 95.0 %}
<span class="text-warning">{{ intensity.difficulty_quality | floatformat:1 }}%</span>
{% else %}
<span class="text-success">{{ intensity.difficulty_quality | floatformat:1 }}%</span>
{% endif %}
{% if intensity.difficulty_quality <= 85.0 %}
<span class="text-danger">
{% elif intensity.difficulty_quality <= 95.0 %}
<span class="text-warning">
{% else %}
<span class="text-success">
{% endif %}
{{ intensity.difficulty_quality | floatformat:1 }}%</span>
</div>
@ -49,12 +51,13 @@
<div class="col-4 col-sm-3 pr-0">Skill</div>
<div class="col-2 text-right pl-0">
{% if intensity.quantity_of_skill_quality <= 85.0 %}
<span class="text-danger">{{ intensity.quantity_of_skill_quality | floatformat:1 }}%</span>
<span class="text-danger">
{% elif intensity.quantity_of_skill_quality <= 95.0 %}
<span class="text-warning">{{ intensity.quantity_of_skill_quality | floatformat:1 }}%</span>
<span class="text-warning">
{% else %}
<span class="text-success">{{ intensity.quantity_of_skill_quality | floatformat:1 }}%</span>
<span class="text-success">
{% endif %}
{{ intensity.quantity_of_skill_quality | floatformat:1 }}%</span>
</div>
@ -64,27 +67,38 @@
<div class="col-4 col-sm-3 pr-0">Passes</div>
<div class="col-2 text-right pl-0">
{% if intensity.number_of_passes_quality <= 85.0 %}
<span class="text-danger">{{ intensity.number_of_passes_quality | floatformat:1 }}%</span>
<span class="text-danger">
{% elif intensity.number_of_passes_quality <= 95.0 %}
<span class="text-warning">{{ intensity.number_of_passes_quality | floatformat:1 }}%</span>
<span class="text-warning">
{% else %}
<span class="text-success">{{ intensity.number_of_passes_quality | floatformat:1 }}%</span>
<span class="text-success">
{% endif %}
{{ intensity.number_of_passes_quality | floatformat:1 }}%</span>
</div>
<div class="col-6 col-sm-5 text-center">{{ intensity.number_of_gymnast }} gymnasts on trampoline</div>
<div class="col-sm-2 d-none d-sm-block"></div>
<div class="col-4 col-sm-3 pr-0"><b>Average</b></div>
<div class="col-4 col-sm-3 pr-0">
{% if intensity.average_training_quality <= 85.0 %}
<span class="text-danger">
{% elif intensity.average_training_quality <= 95.0 %}
<span class="text-warning">
{% else %}
<span class="text-success">
{% endif %}
Average</span>
</div>
<div class="col-2 text-right pl-0">
<b>
{% if intensity.average_training_quality <= 85.0 %}
<span class="text-danger">{{ intensity.average_training_quality | floatformat:1 }}%</span>
<span class="text-danger">
{% elif intensity.average_training_quality <= 95.0 %}
<span class="text-warning">{{ intensity.average_training_quality | floatformat:1 }}%</span>
<span class="text-warning">
{% else %}
<span class="text-success">{{ intensity.average_training_quality | floatformat:1 }}%</span>
<span class="text-success">
{% endif %}
{{ intensity.average_training_quality | floatformat:1 }}%</span>
</b>
</div>
</div>
@ -105,16 +119,26 @@
<div class="col-4 col-sm-3 pr-0">Diff/Skill</div>
<div class="col-2 text-right pl-0">{{ intensity.average_difficulty_by_skill_in_unit | floatformat:3 }}</div>
<div class="col-sm-2 d-none d-sm-block"></div>
<div class="col-4 col-sm-3 pr-0">Time/passe</div>
<div class="col-4 col-sm-3 pr-0">
{% if intensity.passes_quality_for_gymnast >= 3 %}
<span class="text-danger">
{% elif intensity.passes_quality_for_gymnast == 2 %}
<span class="text-warning">
{% else %}
<span class="text-success">
{% endif %}
Time/passe</span>
</div>
<div class="col-2 text-right pl-0">
<b>
{% if intensity.passes_quality_for_gymnast >= 3 %}
<span class="text-danger">{{ intensity.average_time_by_passe_readable }}</span>
<span class="text-danger">
{% elif intensity.passes_quality_for_gymnast == 2 %}
<span class="text-warning">{{ intensity.average_time_by_passe_readable }}</span>
<span class="text-warning">
{% else %}
<span class="text-success">{{ intensity.average_time_by_passe_readable }}</span>
<span class="text-success">
{% endif %}
{{ intensity.average_time_by_passe_readable }}</span>
</b>
</div>
@ -132,8 +156,8 @@
{% if intensity.to_markdown %}
<div class="col-12 mt-3 pt-0">
<h4 class="mb-0">More details</h4>
<div class="col-12 mt-3 pt-0 text-justify">
<p><b><u>Informations</u></b></p>
{{ intensity.to_markdown | safe }}
</div>
{% endif %}

View File

@ -6,22 +6,24 @@
<div class="row">
<div class="col-8">
<h4 class="">
{% if gymnast %}<i><a href="{% url 'gymnast_details_tab' gymnast.id 'routine' %}">{{ gymnast }}</a></i>'s{% endif %} Intensity listing
{% if gymnast %}
{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}<a href="{% url 'gymnast_details_tab' gymnast.id 'routine' %}">{% endif %}{{ gymnast }}{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}</a>{% endif %}'s
{% endif %} Intensities
</h4>
</div>
<div class="col-1 ml-auto">
<div class="text-right">
<a href="{% if gymnast %}{% url 'intensity_create_for_gymnast' gymnast.id %}{% else %}{% url 'intensity_create' %}{% endif %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fas fa-plus"></i>
</button>
</a>
<h3 class="mb-0">
<a href="{% if gymnast %}{% url 'intensity_create_for_gymnast' gymnast.id %}{% else %}{% url 'intensity_create' %}{% endif %}">
<i class="fas fa-plus text-warning"></i>
</a>
</h3>
</div>
</div>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<div class="card-body pt-0 pb-0">
<div class="table-responsive pb-0">
{% if intensity_list %}
<table class="table table-striped tablesorter" id="intensity_table">
<thead>
@ -32,11 +34,11 @@
<th style="width: 18%" class="header text-left">Gymnast</th>
{% endif %}
<th style="width: 7%" class="header text-center">Time</th>
<th style="width: 7%" class="header text-center">Diff</th>
<th style="width: 7%" class="header text-center">Skill</th>
<th style="width: 7%" class="header text-center">Passe</th>
<th style="width: 7%" class="header text-center">Quality</th>
<th style="width: 7%" class="header text-center">Time (%)</th>
<th style="width: 7%" class="header text-center">Diff (%)</th>
<th style="width: 7%" class="header text-center">Skill (%)</th>
<th style="width: 7%" class="header text-center">Passe (%)</th>
<th style="width: 7%" class="header text-center">Quality (%)</th>
<th style="width: 7%" class="header text-center">T/p</th><!-- Time by passe -->
<th style="width: 7%" class="header text-center">D/p</th><!-- Difficulty by passe -->
@ -69,12 +71,13 @@
<td class="text-center">
<b>
{% if intensity.average_training_quality <= 85.0 %}
<span class="text-danger">{{ intensity.average_training_quality | floatformat:1 }}%</span>
<span class="text-danger">
{% elif intensity.average_training_quality <= 95.0 %}
<span class="text-warning">{{ intensity.average_training_quality | floatformat:1 }}%</span>
<span class="text-warning">
{% else %}
<span class="text-success">{{ intensity.average_training_quality | floatformat:1 }}%</span>
<span class="text-success">
{% endif %}
{{ intensity.average_training_quality | floatformat:1 }}</span>
</b>
</td>
@ -82,12 +85,13 @@
<td class="text-center">
<b>
{% if intensity.passes_quality_for_gymnast >= 3 %}
<span class="text-danger">{{ intensity.average_time_by_passe_readable }}</span>
<span class="text-danger">
{% elif intensity.passes_quality_for_gymnast == 2 %}
<span class="text-warning">{{ intensity.average_time_by_passe_readable }}</span>
<span class="text-warning">
{% else %}
<span class="text-success">{{ intensity.average_time_by_passe_readable }}</span>
<span class="text-success">
{% endif %}
{{ intensity.average_time_by_passe_readable }}</span>
</b>
</td>
<!-- Difficulty by passe -->
@ -129,7 +133,7 @@
headers: {
0: { sorter: false },
},
dateFormat: "uk",
dateFormat : "ddmmyyyy",
sortList: [[1, 1], [2, 1]]
});

View File

@ -16,7 +16,7 @@
<label for="id_date" class="col-4 col-sm-3 col-form-label">Date</label>
<div class="col-sm-6 col-md-5 col-lg-4 col-xl-3 {% if form.date.errors %}has-danger{% endif %}">
{{ form.date }}
{% if form.date.errors %}<span class="btn btn-sm btn-danger-outline">{% for error in form.date.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.date.errors %}<span class="btn btn-sm">{% for error in form.date.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
@ -25,7 +25,7 @@
{% if request.user|has_group:"trainer" %}
{{ form.gymnast }}
{{ form.gymnast_related }}
{% if form.gymnast.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.gymnast.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% else %}
<input type="text" class="form-control" value="{{ request.user.first_name }} {{ request.user.last_name }}" readonly="readonly" />
<input type="hidden" name="gymnast" id="gymnast" value="{{ request.user.gymnast.id }}" />
@ -38,14 +38,14 @@
<div class="col-8 col-md-9 col-lg-6 {% if form.skill.errors %}has-danger{% endif %}">
{{ form.skill }}
{{ form.skill_related }}
{% if form.skill.errors %}&nbsp;<skilln class="btn btn-sm btn-danger-outline">{% for error in form.skill.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.skill.errors %}&nbsp;<skilln class="btn btn-sm">{% for error in form.skill.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_learning_step" class="col-4 col-sm-3 col-form-label">Learning step</label>
<div class="col-8 col-sm-4 col-md-3 {% if form.learning_step.errors %}has-danger{% endif %}">
{{ form.learning_step }}
{% if form.learning_step.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.learning_step.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.learning_step.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.learning_step.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
{% if plan_id %}
@ -53,7 +53,7 @@
<label for="id_is_done" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-3 col-form-label">Is Done</label>
<div class="col-8 col-sm-2 col-md-2 col-lg-2 col-xl-2">
{{ form.is_done }}
{% if form.is_done.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.is_done.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.is_done.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.is_done.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
{% endif %}

View File

@ -22,7 +22,7 @@
class="col-8 col-md-9 col-lg-6 col-lg-4 col-xl-4 {% if form.gymnast.errors %}has-danger{% endif %}">
{{ form.gymnast }}
{{ form.gymnast_related }}
{% if form.gymnast.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.gymnast.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row {% if form.title.errors %}has-error has-feedback{% endif %}">
@ -30,7 +30,7 @@
class="text-danger"><b>*</b></label>
<div class="col-8 col-md-9 col-lg-6 col-lg-4 col-xl-4">
{{ form.title }}
{% if form.title.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.title.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.title.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.title.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
@ -39,7 +39,7 @@
<div
class="col-8 col-sm-6 col-md-4 col-lg-4 col-xl-3 {% if form.date.errors %}has-danger{% endif %}">
{{ form.date }}
{% if form.date.errors %}<span class="btn btn-sm btn-danger-outline">{% for error in form.date.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.date.errors %}<span class="btn btn-sm">{% for error in form.date.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
@ -57,7 +57,7 @@
<div
class="col-8 col-sm-5 col-md-4 col-lg-4 col-xl-4 {% if form.status.errors %}has-danger{% endif %}">
{{ form.status }}
{% if form.status.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.status.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.status.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.status.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group text-center">

View File

@ -1,18 +1,27 @@
{% extends "base.html" %}
{% block content %}
<div class="card mb-0">
<div class="card-header">
<h3 class="mb-0"><a href="{% url 'gymnast_details_tab' note.gymnast.id 'scores' %}">{{ note.gymnast }}</a> - {{ note.title }}</h3>
<p class="card-title text-muted"><b>{{ note.date | date:'j N Y' }}</b></p>
</div>
<div class="card-body pb-0 mb-0">
<div class="row mr-1 ml-1 pb-0 mb-0">
<div class="col-md-12">
<div class="row">
<div class="col-md-8 offset-md-2">
<div class="card mb-0">
<div class="card-header row">
<div class="col-10">
<h3 class="mb-0"><a href="{% url 'gymnast_details_tab' note.gymnast.id 'scores' %}">{{ note.gymnast }}</a> - {{ note.title }}</h3>
<p class="card-title text-muted"><b>{{ note.date | date:'j N Y' }}</b></p>
</div>
{% if request.user.id == note.coach.id %}
<div class="col-1 ml-auto text-right">
<a href="{% url 'note_update' note.id %}">
<span class="tim-icons icon-pencil text-warning"></span>
</a>
</div>
{% endif %}
</div>
<div class="card-body text-justify">
<p>{{ note.to_markdown | safe }}</p>
<p class="text-right">{{ note.coach }}</p>
</div>
</div>
<a href="{% url 'note_update' note.id %}"><span class="tim-icons icon-pencil text-warning"></span></a><br /><br />
</div>
</div>

View File

@ -6,7 +6,15 @@
<div class="row">
<div class="col-8">
<h4 class="">
{% if gymnast %}<i><a href="#">{{ gymnast }}</a></i>'s{% endif %} notes listing
{% if gymnast %}
{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}
<a href="{% url 'gymnast_details_tab' gymnast.id 'event' %}">
{% endif %}
{{ gymnast }}
{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}
</a>
{% endif %}'s
{% endif %} notes
</h4>
</div>
<div class="col-1 ml-auto">
@ -20,34 +28,53 @@
</div>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<div class="card-body pt-0 pb-0">
<div class="table-responsive pb-0">
{% if note_list %}
<table class="table table-striped tablesorter" id="chrono_table">
<thead>
<tr>
<th style="width: 5%">&nbsp;</th>
<th style="width: 10%" class="header">Date</th>
<th style="width: 25%" class="header text-left">Gymnast</th>
<th style="width: 25%" class="header text-left">Coach</th>
<th style="width: 35%" class="header text-left">Title</th>
{% if not gymnast %}
<th style="width: 15%" class="header text-left">Gymnast</th>
{% endif %}
<th style="width: 15%" class="header text-left">Coach</th>
</tr>
</thead>
<tbody>
{% for note in note_list %}
<tr role="row" class="{% cycle 'odd' 'even' %}">
<td>
<td class="text-left">
<a href="{% url 'note_update' note.id %}">
<span class="tim-icons icon-pencil text-warning"></span>
</a>
</td>
<td>
<a href="{% url 'note_details' note.id %}">{{ note.created_at | date:"d-m-Y" }}</a>
<a href="{% url 'note_details' note.id %}">
{{ note.created_at | date:"d-m-Y" }}
</a>
</td>
<td class="text-left">{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}<a href="{% url 'gymnast_details' note.gymnast.id %}">{% endif %}{{ note.gymnast}}</a></td>
<td>{{ note.title }}</td>
{% if not gymnast %}
<td class="text-left">
{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}
<a href="{% url 'gymnast_details' note.gymnast.id %}">
{% endif %}
{{ note.gymnast}}
{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}
</a>
{% endif %}
</td>
{% endif %}
<td class="text-left">{{ note.coach }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p class="text-muted">There are no chronos corresponding to your criterias.</p>
<p class="text-muted">There are no chronos corresponding to your criterias.</p>
{% endif %}
</div>
</div>
@ -61,8 +88,12 @@
headers: {
0: { sorter: false },
},
dateFormat: "uk",
sortList: [[1, 1], [2, 1]]
dateFormat : "ddmmyyyy",
{% if not gymnast %}
sortList: [[1, 1], [3, 1], [2, 1]],
{% else %}
sortList: [[1, 1], [2, 1]],
{% endif %}
});
$('#chrono_table').DataTable({
@ -71,7 +102,7 @@
paging: false,
searching: false,
ordering: false,
// "bInfo" : false,
"bInfo": false,
});
});
</script>

View File

@ -16,7 +16,7 @@
<label for="id_date" class="col-4 col-sm-3 col-form-label">Date <span class="text-danger"><b>*</b></span></label>
<div class="col-sm-6 col-md-5 col-lg-4 col-xl-2 {% if form.date.errors %}has-danger{% endif %}">
{{ form.date }}
{% if form.date.errors %}<span class="btn btn-sm btn-danger-outline">{% for error in form.date.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.date.errors %}<span class="btn btn-sm">{% for error in form.date.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
@ -25,7 +25,7 @@
{% if request.user|has_group:"trainer" %}
{{ form.gymnast }}
{{ form.gymnast_related }}
{% if form.gymnast.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.gymnast.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% else %}
<input type="text" class="form-control" value="{{ request.user.first_name }} {{ request.user.last_name }}" readonly="readonly" />
<input type="hidden" name="gymnast" id="gymnast" value="{{ request.user.gymnast.id }}" />
@ -37,14 +37,14 @@
<div class="col-8 col-sm-8 col-md-6 col-lg-6 col-xl-6 {% if form.educative.errors %}has-danger{% endif %}">
{{ form.educative }}
{{ form.educative_related }}
{% if form.educative.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.educative.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.educative.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.educative.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_learning_step" class="col-4 col-sm-3 col-form-label">Learning step</label>
<div class="col-8 col-sm-4 col-md-3 {% if form.learning_step.errors %}has-danger{% endif %}">
{{ form.learning_step }}
{% if form.learning_step.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.learning_step.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.learning_step.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.learning_step.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">

View File

@ -18,7 +18,7 @@
{% if request.user|has_group:"trainer" %}
{{ form.gymnast }}
{{ form.gymnast_related }}
{% if form.gymnast.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.gymnast.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% else %}
<input type="text" class="form-control" value="{{ request.user.first_name }} {{ request.user.last_name }}" readonly="readonly" />
<input type="hidden" name="gymnast" id="gymnast" value="{{ request.user.gymnast.id }}" />
@ -67,7 +67,7 @@
<label for="id_number_of_successes" class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-3 col-form-label"># success <span class="text-danger"><b>*</b></span></label>
<div class="col-4 col-sm-2 col-md-4 col-lg-2 {% if form.number_of_successes.errors %}has-danger{% endif %}">
{{ form.number_of_successes }}
{% if form.number_of_successes.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.number_of_successes.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.number_of_successes.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.number_of_successes.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
@ -75,7 +75,7 @@
<label for="id_number_of_try" class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-3 col-form-label"># try <span class="text-danger"><b>*</b></span></label>
<div class="col-4 col-sm-2 col-md-4 col-lg-2 {% if form.number_of_try.errors %}has-danger{% endif %}">
{{ form.number_of_try }}
{% if form.number_of_try.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.number_of_try.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.number_of_try.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.number_of_try.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>

View File

@ -8,7 +8,15 @@
<div class="card-header row">
<div class="col-8">
<h4 class="">
{% if gymnast %}<i><a href="{% url 'gymnast_details_tab' gymnast.id 'routine' %}"><i>{{ gymnast }}</i></a>'s {% endif %} routine done listing
{% if gymnast %}
{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}
<a href="{% url 'gymnast_details_tab' gymnast.id 'routine' %}">
{% endif %}
{{ gymnast }}
{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}
</a>
{% endif %}'s
{% endif %} routine done
</h4>
</div>
<div class="col-1 ml-auto">
@ -44,17 +52,27 @@
<span class="tim-icons icon-pencil text-warning"></span>
</a>
</td>
<td class="text-center">{{ routine_done.date | date:"d-m-Y"}}</td>
<td class="text-center">{{ routine_done.get_routine_type_display }}</td>
<td class="text-center">
{{ routine_done.date | date:"d-m-Y"}}
</td>
<td class="text-center">
{{ routine_done.get_routine_type_display }}
</td>
<td class="text-left">
{% if routine_done.routine %}
<a href="{% url 'combination_details' routine_done.routine.id %}">{{ routine_done.routine.long_label }}</a>
<a href="{% url 'combination_details' routine_done.routine.id %}">
{{ routine_done.routine.long_label }}
</a>
{% else %}
-
-
{% endif %}
</td>
<td class="text-center">{{ routine_done.number_of_try }}</td>
<td class="text-center">{{ routine_done.number_of_successes }}</td>
<td class="text-center">
{{ routine_done.number_of_try }}
</td>
<td class="text-center">
{{ routine_done.number_of_successes }}
</td>
</tr>
{% endfor %}
</tbody>
@ -76,7 +94,7 @@
headers: {
0: { sorter: false },
},
dateFormat: "uk",
dateFormat : "ddmmyyyy",
sortList: [[1, 1]]
});

View File

@ -19,7 +19,7 @@
{% if request.user|has_group:"trainer" %}
{{ form.gymnast }}
{{ form.gymnast_related }}
{% if form.gymnast.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.gymnast.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% else %}
<input type="text" class="form-control" value="{{ request.user.first_name }} {{ request.user.last_name }}" readonly="readonly" />
<input type="hidden" name="gymnast" id="gymnast" value="{{ request.user.gymnast.id }}" />
@ -32,7 +32,7 @@
{{ form.event }}
{{ form.event_related }}
{% if form.event.errors %}
<label class="btn btn-sm btn-danger-outline">
<label class="btn btn-sm">
{% for error in form.event.errors %}{{ error }}{% endfor %}
</label>
{% endif %}
@ -43,7 +43,7 @@
<label for="id_routine_type" class="col-3 col-sm-3 col-md-3 col-lg-3 col-xl-2 col-form-label">Routine <span class="text-danger"><b>*</b></span></label>
<div class="col-5 col-sm-3 col-md-4 {% if form.routine_type.errors %}has-danger{% endif %}">
{{ form.routine_type }}
{% if form.routine_type.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.routine_type.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.routine_type.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.routine_type.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">

View File

@ -8,17 +8,25 @@
<div class="card-header row">
<div class="col-8">
<h4 class="">
{% if gymnast %}<a href="{% url 'gymnast_details_tab' gymnast.id 'scores' %}"><i>{{ gymnast }}</i></a>'s {% endif %} Scores listing
{% if gymnast %}
{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}
<a href="{% url 'gymnast_details_tab' gymnast.id 'scores' %}">
{% endif %}
{{ gymnast }}
{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}
</a>
{% endif %}'s
{% endif %} Scores
</h4>
</div>
<div class="col-1 ml-auto">
<div class="text-right">
{% if request.user|has_group:"trainer" %}
<a href="{% if gymnast %}{% url 'score_create_for_gymnast' gymnast.id %}{% else %}{% url 'score_create' %}{% endif %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fas fa-plus"></i>
</button>
</a>
<h3 class="mb-0">
<a href="{% if gymnast %}{% url 'score_create_for_gymnast' gymnast.id %}{% else %}{% url 'score_create' %}{% endif %}">
<i class="fas fa-plus text-warning"></i>
</a>
</h3>
{% endif %}
</div>
</div>
@ -33,8 +41,8 @@
<th class="header text-left">Gymnast</th>
{% endif %}
<th class="header text-left">Event</th>
<th class="header text-left">Date</th>
<th class="header text-left">Routine</th>
<th class="header text-center">Date</th>
<th class="header text-center">Routine</th>
<th class="header text-center">Exe.</th>
<th class="header text-center">Dif.</th>
<th class="header text-center">ToF</th>
@ -52,7 +60,15 @@
</a>
</td>
{% if not gymnast %}
<td>{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}<a href="{% url 'gymnast_details' score.gymnast.id %}">{% endif %}{{ score.gymnast }}</a></td>
<td>
{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}
<a href="{% url 'gymnast_details' score.gymnast.id %}">
{% endif %}
{{ score.gymnast }}
{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}
</a>
{% endif %}
</td>
{% endif %}
<td><a href="{% url 'event_details' score.event.id %}">{{ score.event.name }}</a></td>
<td class="text-center">{{ score.event.date_begin | date:"j-n-Y" }}</td>
@ -62,9 +78,12 @@
<td class="text-center">{{ score.point_time_of_flight }}</td>
<td class="text-center">{{ score.point_horizontal_displacement }}</td>
<td class="text-center">
{% if score.penality > 0 %}-{{ score.penality }}
{% else %}-
{% endif %}</td>
{% if score.penality > 0 %}
-{{ score.penality }}
{% else %}
-
{% endif %}
</td>
<td class="text-center"><b>{{ score.total }}</b></td>
</tr>
{% endfor %}
@ -86,7 +105,7 @@
headers: {
0: { sorter: false },
},
dateFormat: "uk",
dateFormat : "ddmmyyyy",
sortList: [[1, 0], [3, 1], [4, 0]]
});

View File

@ -14,6 +14,7 @@
action="{% if season_information_id %}{% url 'season_information_update' season_information_id %}{% else %}{% url 'season_information_create' %}{% endif %}"
method="post" class="form-horizontal" id="formulaire" name="formulaire">
{% csrf_token %}
<div class="form-group row ">
<label for="id_date" class="col-sm-3 col-md-3 col-lg-3 col-xl-3 col-form-label">Gymnast
<span class="text-danger"><b>*</b></span></label>
@ -21,62 +22,79 @@
class="col-sm-9 col-md-9 col-lg-6 {% if form.gymnast.errors %}has-danger{% endif %}">
{{ form.gymnast }}
{{ form.gymnast_related }}
{% if form.gymnast.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.gymnast.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.gymnast.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_season" class="col-sm-3 col-md-3 col-lg-3 col-xl-3 col-form-label">Season <span class="text-danger"><b>*</b></span></label>
<div
class="col-sm-3 col-md-4 col-lg-4 col-xl-3 {% if form.season.errors %}has-danger{% endif %}">
{{ form.season }}
{% if form.season.errors %}<span class="btn btn-sm btn-danger-outline">{% for error in form.season.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.season.errors %}<span class="btn btn-sm">{% for error in form.season.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_club" class="col-4 col-sm-3 col-form-label">Club <span class="text-danger"><b>*</b></span></label>
<div class="col-8 col-md-9 col-lg-6 {% if form.club.errors %}has-danger{% endif %}">
<div class="col-8 col-md-9 {% if form.club.errors %}has-danger{% endif %}">
{{ form.club }}
{{ form.club_related }}
{% if form.club.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.club.errors %}{{error}}{% endfor %}</span>{% endif %}
{% if form.club.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.club.errors %}{{error}}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_number_of_training_sessions_per_week" class="col-sm-3 col-md-3 col-lg-3 col-xl-3 col-form-label">Training/week <span class="text-danger"><b>*</b></span></label>
<div class="col-sm-3 col-md-3 col-lg-2 {% if form.number_of_training_sessions_per_week.errors %}has-danger{% endif %}">
{{ form.number_of_training_sessions_per_week }}
{% if form.number_of_training_sessions_per_week.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.number_of_training_sessions_per_week.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.number_of_training_sessions_per_week.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.number_of_training_sessions_per_week.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_number_of_hours_per_week" class="col-sm-3 col-md-3 col-lg-3 col-xl-3 col-form-label">Hours/week <span class="text-danger"><b>*</b></span></label>
<div class="col-sm-3 col-md-3 col-lg-2 {% if form.number_of_hours_per_week.errors %}has-danger{% endif %}">
{{ form.number_of_hours_per_week }}
{% if form.number_of_hours_per_week.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.number_of_hours_per_week.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.number_of_hours_per_week.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.number_of_hours_per_week.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_number_of_s_and_c_sessions_per_week" class="col-sm-3 col-md-3 col-lg-3 col-xl-3 col-form-label">S&C Training/week</label>
<div class="col-sm-3 col-md-3 col-lg-2 {% if form.number_of_s_and_c_sessions_per_week.errors %}has-danger{% endif %}">
{{ form.number_of_s_and_c_sessions_per_week }}
{% if form.number_of_s_and_c_sessions_per_week.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.number_of_s_and_c_sessions_per_week.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.number_of_s_and_c_sessions_per_week.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.number_of_s_and_c_sessions_per_week.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_number_of_s_and_c_hours_per_week" class="col-sm-3 col-md-3 col-lg-3 col-xl-3 col-form-label">S&C Hours/week</label>
<div class="col-sm-3 col-md-3 col-lg-2 {% if form.numbernumber_of_s_and_c_hours_per_week_of_hours_per_week.errors %}has-danger{% endif %}">
{{ form.number_of_s_and_c_hours_per_week }}
{% if form.number_of_s_and_c_hours_per_week.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.number_of_s_and_c_hours_per_week.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.number_of_s_and_c_hours_per_week.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.number_of_s_and_c_hours_per_week.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_category" class="col-sm-3 col-md-3 col-lg-3 col-xl-3 col-form-label">Category <span class="text-danger"><b>*</b></span></label>
<div class="col-sm-3 col-md-3 col-lg-3 {% if form.category.errors %}has-danger{% endif %}">
{{ form.category }}
{% if form.category.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.category.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.category.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.category.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_information" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Informations</label>
</div>
<div class="form-group row">
<div class="col-12 {% if form.id_informations.errors %}has-danger{% endif %}">
{{ form.informations }}
</div>
</div>
<div class="form-group text-center">
<input type="submit" value="{% if note_id %}Update{% else %}Add{% endif %}"
<input type="submit" value="{% if season_information_id %}Update{% else %}Add{% endif %}"
class="btn btn-warning" />
</div>
</form>

View File

@ -0,0 +1,80 @@
{% extends "base.html" %}
{% block content %}
<div class="row justify-content-center">
<div class="col-12 col-sm-12 col-md-8 col-lg-6 col-xl-6">
<div class="card">
<div class="card-header">
<h4 class=""><a href="{% url 'gymnast_details_tab' season_information.gymnast.id 'season_informations' %}"><i>{{ season_information.gymnast }}</i></a>' Season {{ season_information.season }} informations</h4>
</div>
<div class="card-body">
<form class="form-horizontal" id="formulaire" name="formulaire">
{% csrf_token %}
<div class="form-group row mb-0">
<label for="id_season" class="col-sm-3 col-md-3 col-lg-3 col-xl-3 col-form-label">Season</label>
<div class="col-sm-3 col-md-4 col-lg-4 col-xl-3 pt-2">
{{ season_information.season }}
</div>
</div>
<div class="form-group row mb-0">
<label for="id_club" class="col-4 col-sm-3 col-form-label">Club</label>
<div class="col-8 col-md-9 pt-2">
{{ season_information.club.name }}
</div>
</div>
<div class="form-group row mb-0">
<label for="id_number_of_training_sessions_per_week" class="col-sm-3 col-md-3 col-lg-3 col-xl-3 col-form-label">Training/week</label>
<div class="col-sm-3 col-md-3 col-lg-2 pt-2">
{{ season_information.number_of_training_sessions_per_week }} t/w
</div>
</div>
<div class="form-group row mb-0">
<label for="id_number_of_hours_per_week" class="col-sm-3 col-md-3 col-lg-3 col-xl-3 col-form-label">Hours/week</label>
<div class="col-sm-3 col-md-3 col-lg-2 pt-2">
{{ season_information.number_of_hours_per_week }} h/w
</div>
</div>
<div class="form-group row mb-0">
<label for="id_number_of_s_and_c_sessions_per_week" class="col-sm-3 col-md-3 col-lg-3 col-xl-3 col-form-label">S&C Training/week</label>
<div class="col-sm-3 col-md-3 col-lg-2 pt-2">
{{ season_information.number_of_s_and_c_sessions_per_week }} t/w
</div>
</div>
<div class="form-group row mb-0">
<label for="id_number_of_s_and_c_hours_per_week" class="col-sm-3 col-md-3 col-lg-3 col-xl-3 col-form-label">S&C Hours/week</label>
<div class="col-sm-3 col-md-3 col-lg-2 pt-2">
{{ season_information.number_of_s_and_c_hours_per_week }} h/w
</div>
</div>
<div class="form-group row mb-0">
<label for="id_category" class="col-sm-3 col-md-3 col-lg-3 col-xl-3 col-form-label">
Category
</label>
<div class="col-sm-3 col-md-3 col-lg-3 pt-2">
{{ season_information.category.long_label }}
</div>
</div>
{% if season_information.informations %}
<div class="form-group row mb-0">
<label for="id_information" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Informations</label>
</div>
<div class="form-group row">
<div class="col-12 ml-2">
{{ season_information.informations }}
</div>
</div>
{% endif %}
</form>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -14,7 +14,7 @@
<div class="col-1 ml-auto">
<div class="text-right">
{% if request.user|has_group:"trainer" %}
<a href="{% if gymnast %}{% url 'add_season_information_for_gymnast' gymnast.id %}{% else %}{% url 'season_information_create' %}{% endif %}">
<a href="{% if gymnast %}{% url 'season_information_create_for_gymnast' gymnast.id %}{% else %}{% url 'season_information_create' %}{% endif %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fas fa-plus"></i>
</button>
@ -75,7 +75,7 @@
headers: {
0: { sorter: false },
},
dateFormat: "uk",
dateFormat : "ddmmyyyy",
sortList: [[2, 1]]
});

View File

@ -14,14 +14,14 @@
{% csrf_token %}
<div class="form-group row ">
<label for="id_gymnast" class="col-4 col-sm-3 col-md-4 col-lg-4 col-xl-3 col-form-label">Gymnast <span class="text-danger"><b>*</b></span></label>
<div class="col-8 col-sm-9 col-md-8 col-lg-8 col-lg-8 col-xl-9 {% if form.gymnast.errors %}has-danger{% endif %}">
<div class="col-8 col-sm-9 col-md-8 col-lg-8 col-lg-8 col-xl-6 {% if form.gymnast.errors %}has-danger{% endif %}">
{% if request.user|has_group:"trainer" %}
{{ form.gymnast }}
{{ form.gymnast_related }}
{% if form.gymnast.errors %}
<label class="text-danger" for="id_gymnast" id="gymnast-error">
<span class="btn btn-sm btn-danger">
{% for error in form.gymnast.errors %}{{ error }}{% endfor %}
</label>
</span>
{% endif %}
{% else %}
<input type="text" class="form-control" value="{{ request.user.first_name }} {{ request.user.last_name }}" readonly="readonly" />
@ -33,84 +33,119 @@
<label for="id_date" class="col-4 col-sm-3 col-md-4 col-lg-4 col-xl-3 col-form-label">Date <span class="text-danger"><b>*</b></span></label>
<div class="col-5 col-sm-3 col-md-4 col-lg-4 col-xl-3 {% if form.date.errors %}has-danger{% endif %}">
{{ form.date }}
{% if form.date.errors %}<span class="btn btn-sm btn-danger-outline">{% for error in form.date.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_event" class="col-4 col-sm-3 col-md-4 col-lg-4 col-xl-3 col-form-label">Event</label>
<div class="col-8 col-sm-8 col-md-8 col-lg-8 col-xl-9 {% if form.date.errors %}has-danger{% endif %}">
{{ form.event }}
{{ form.event_related }}
{% if form.eventt.errors %}
<label class="text-danger" for="id_eventt" id="event-error">
{% for error in form.event.errors %}{{ error }}{% endfor %}
</label>
{% if form.date.errors %}
<span class="btn btn-sm btn-danger">
{% for error in form.date.errors %}
{{ error }}
{% endfor %}
</span>
{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_mindstate" class="col-4 col-sm-3 col-md-4 col-lg-4 col-xl-3 col-form-label">Mind State <span class="text-danger"><b>*</b></span></label>
<div class="col-5 col-sm-2 col-md-3 col-lg-2 {% if form.mindstate.errors %}has-danger{% endif %}">
{{ form.mindstate }}
{% if form.mindstate.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.mindstate.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
<div class="col-4 col-sm-3 col-md-5 col-lg-5 pl-0 pr-0">
<p class="text-muted text-form-info mb-0 mt-2">(1: Very Bad - 10: Very Good)</p>
</div>
</div>
<div class="form-group row ">
<label for="id_sleep" class="col-4 col-sm-3 col-md-4 col-lg-4 col-xl-3 col-form-label">Sleep <span class="text-danger"><b>*</b></span></label>
<div class="col-5 col-sm-2 col-md-3 col-lg-2 {% if form.sleep.errors %}has-danger{% endif %}">
{{ form.sleep }}
{% if form.sleep.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.sleep.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
<div class="col-4 col-sm-3 col-md-5 col-lg-5 pl-0 pr-0">
<p class="text-muted text-form-info mb-0 mt-2">(1: Very Bad - 10: Very Good)</p>
</div>
</div>
<div class="form-group row ">
<label for="id_stress" class="col-4 col-sm-3 col-md-4 col-lg-4 col-xl-3 col-form-label">Stress <span class="text-danger"><b>*</b></span></label>
<div class="col-5 col-sm-2 col-md-3 col-lg-2 {% if form.stress.errors %}has-danger{% endif %}">
{{ form.stress }}
{% if form.stress.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.stress.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
<div class="col-4 col-sm-3 col-md-5 col-lg-5 pl-0 pr-0">
<p class="text-muted text-form-info mb-0 mt-2">(1: Very Low - 10: Very High)</p>
</div>
</div>
<div class="form-group row ">
<label for="id_fatigue" class="col-4 col-sm-3 col-md-4 col-lg-4 col-xl-3 col-form-label">Fatigue <span class="text-danger"><b>*</b></span></label>
<div class="col-5 col-sm-2 col-md-3 col-lg-2 {% if form.fatigue.errors %}has-danger{% endif %}">
{{ form.fatigue }}
{% if form.fatigue.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.fatigue.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
<div class="col-4 col-sm-3 col-md-5 col-lg-5 pl-0 pr-0">
<p class="text-muted text-form-info mb-0 mt-2">(1: Very Low - 10: Very High)</p>
</div>
</div>
<div class="form-group row ">
<label for="id_muscle_soreness" class="col-4 col-sm-3 col-md-4 col-lg-4 col-xl-3 col-form-label">Muscle Soreness <span class="text-danger"><b>*</b></span></label>
<div class="col-5 col-sm-2 col-md-3 col-lg-2 {% if form.muscle_soreness.errors %}has-danger{% endif %}">
{{ form.muscle_soreness }}
{% if form.muscle_soreness.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.muscle_soreness.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
<div class="col-4 col-sm-3 col-md-5 col-lg-5 pl-0 pr-0">
<p class="text-muted text-form-info mb-0 mt-2">(1: Very Low - 10: Very High)</p>
<label for="id_event" class="col-4 col-sm-3 col-md-4 col-lg-4 col-xl-3 col-form-label">Event</label>
<div class="col-8 col-sm-8 col-md-8 col-lg-8 col-xl-6 {% if form.date.errors %}has-danger{% endif %}">
{{ form.event }}
{{ form.event_related }}
{% if form.event.errors %}
<span class="btn btn-sm btn-danger">
{% for error in form.event.errors %}
{{ error }}
{% endfor %}
</span>
{% endif %}
</div>
</div>
<div class="form-group row">
<label class="col-12 text-center text-danger" id="note_info"><b>Merci de donner des détails concernant les scores.</b></label>
<label for="id_mindstate" class="col-4 col-xl-3 col-form-label">Mind State <span class="text-danger"><b>*</b></span></label>
<div class="col-6 col-xl-7 pr-0 {% if form.mindstate.errors %}has-danger{% endif %}">
{{ form.mindstate }}
{% if form.mindstate.errors %}
<span class="btn btn-sm btn-danger">
{% for error in form.mindstate.errors %}
{{ error }}
{% endfor %}
</span>
{% endif %}
</div>
<label for="id_mindstate" class="col-2 mt-2 text-center" id="mindstate_value"></label>
</div>
<div class="form-group row ">
<label for="id_sleep" class="col-4 col-sm-3 col-md-4 col-lg-4 col-xl-3 col-form-label">Sleep <span class="text-danger"><b>*</b></span></label>
<div class="col-6 col-xl-7 pr-0 {% if form.sleep.errors %}has-danger{% endif %}">
{{ form.sleep }}
{% if form.sleep.errors %}
<span class="btn btn-sm btn-danger">
{% for error in form.sleep.errors %}
{{ error }}
{% endfor %}
</span>
{% endif %}
</div>
<label for="id_sleep" class="col-2 mt-2 text-center" id="sleep_value"></label>
</div>
<div class="form-group row ">
<label for="id_stress" class="col-4 col-sm-3 col-md-4 col-lg-4 col-xl-3 col-form-label">Stress <span class="text-danger"><b>*</b></span></label>
<div class="col-6 col-xl-7 pr-0 {% if form.stress.errors %}has-danger{% endif %}">
{{ form.stress }}
{% if form.stress.errors %}
<span class="btn btn-sm btn-danger">
{% for error in form.stress.errors %}
{{ error }}
{% endfor %}
</span>
{% endif %}
</div>
<label for="id_stress" class="col-2 mt-2 text-center" id="stress_value"></label>
</div>
<div class="form-group row ">
<label for="id_fatigue" class="col-4 col-sm-3 col-md-4 col-lg-4 col-xl-3 col-form-label">Fatigue <span class="text-danger"><b>*</b></span></label>
<div class="col-6 col-xl-7 pr-0 {% if form.fatigue.errors %}has-danger{% endif %}">
{{ form.fatigue }}
{% if form.fatigue.errors %}
<span class="btn btn-sm btn-danger">
{% for error in form.fatigue.errors %}
{{ error }}
{% endfor %}
</span>
{% endif %}
</div>
<label for="id_fatigue" class="col-2 mt-2 text-center" id="fatigue_value"></label>
</div>
<div class="form-group row ">
<label for="id_muscle_soreness" class="col-4 col-sm-3 col-md-4 col-lg-4 col-xl-3 col-form-label">Muscle Soreness <span class="text-danger"><b>*</b></span></label>
<div class="col-6 col-xl-7 pr-0 {% if form.muscle_soreness.errors %}has-danger{% endif %}">
{{ form.muscle_soreness }}
{% if form.muscle_soreness.errors %}
<span class="btn btn-sm btn-danger">
{% for error in form.muscle_soreness.errors %}
{{ error }}
{% endfor %}
</span>
{% endif %}
</div>
<label for="id_muscle_soreness" class="col-2 mt-2 text-center" id="muscle_soreness_value"></label>
<!-- <div class="col-4 col-sm-3 col-md-5 col-lg-5 pl-0 pr-0">
<p class="text-muted text-form-info mb-0 mt-2"><small>(1: Very Low - 10: Very High)</small></p>
</div> -->
</div>
<div class="form-group row mb-0">
<label class="col-12 text-center text-danger mb-0" id="note_info"><b>Please provide details regarding the scores.</b></label>
</div>
<div class="form-group row ">
<label for="id_information" class="col-4 col-sm-3 col-md-4 col-lg-4 col-xl-3 col-form-label">Informations <span class="text-danger" id="span_info_required"><b>*</b></span></label>
<div class="col-8 col-sm-8 col-md-8 col-lg-8 col-xl-9 {% if form.id_information.errors %}has-danger{% endif %}">
</div>
<div class="form-group row ">
<div class="col-12 {% if form.id_information.errors %}has-danger{% endif %}">
{{ form.informations }}
</div>
</div>
<div class="form-group text-center">
<div class="form-group text-center" id="div_submit">
<input type="submit" value="{% if wellbeing_id %}Update{% else %}Add{% endif %}" class="btn btn-warning" />
</div>
</form>
</div>
</div>
@ -119,78 +154,145 @@
{% endblock %}
{% block footerscript %}
<script type="text/javascript" >
$().ready(function(){
$("#note_info").hide();
$("#span_info_required").hide();
<script type="text/javascript" >
var mindstate_slider = document.getElementById("id_mindstate");
var sleep_slider = document.getElementById("id_sleep");
var stress_slider = document.getElementById("id_stress");
var fatigue_slider = document.getElementById("id_fatigue");
var muscle_soreness_slider = document.getElementById("id_muscle_soreness");
function are_informations_too_short()
{
if($('#id_informations').val().length < 10)
return true;
// mindstate_slider.min = 1;
// mindstate_slider.value = 5;
// sleep_slider.min = 1;
// sleep_slider.value = 5;
// stress_slider.min = 1;
// stress_slider.value = 5;
// fatigue_slider.min = 1;
// fatigue_slider.value = 5;
// muscle_soreness_slider.min = 1;
// muscle_soreness_slider.value = 5;
var output_sleep = document.getElementById("sleep_value");
var output_mindstate = document.getElementById("mindstate_value");
var output_stress = document.getElementById("stress_value");
var output_fatigue = document.getElementById("fatigue_value");
var output_muscle_soreness = document.getElementById("muscle_soreness_value");
output_mindstate.innerHTML = mindstate_slider.value;
output_sleep.innerHTML = sleep_slider.value;
output_stress.innerHTML = stress_slider.value;
output_fatigue.innerHTML = fatigue_slider.value;
output_muscle_soreness.innerHTML = muscle_soreness_slider.value;
mindstate_slider.oninput = function(){
if(this.value < 5)
output_mindstate.innerHTML = '<b class="text-danger">' + this.value + '</b>';
else
return false;
};
function check_form_values()
{
var test = is_value_lower($('#id_mindstate').val());
test = test || is_value_lower($('#id_sleep').val());
test = test || is_value_upper($('#id_stress').val());
test = test || is_value_upper($('#id_fatigue').val());
test = test || is_value_upper($('#id_muscle_soreness').val());
return test
output_mindstate.innerHTML = this.value;
}
sleep_slider.oninput = function(){
if(this.value < 5)
output_sleep.innerHTML = '<b class="text-danger">' + this.value + '</b>';
else
output_sleep.innerHTML = this.value;
}
stress_slider.oninput = function(){
if(this.value > 5)
output_stress.innerHTML = '<b class="text-danger">' + this.value + '</b>';
else
output_stress.innerHTML = this.value;
}
fatigue_slider.oninput = function(){
if(this.value > 5)
output_fatigue.innerHTML = '<b class="text-danger">' + this.value + '</b>';
else
output_fatigue.innerHTML = this.value;
}
muscle_soreness_slider.oninput = function(){
if(this.value > 5)
output_muscle_soreness.innerHTML = '<b class="text-danger">' + this.value + '</b>';
else
output_muscle_soreness.innerHTML = this.value;
}
function is_value_lower(value)
{
if(value <= 5)
return true
else
return false
};
$().ready(function(){
$("#note_info").hide();
$("#span_info_required").hide();
function is_value_upper(value)
{
if(value >= 5)
return true
else
return false
};
function is_information_field_too_short()
{
if($('#id_informations').val().length < 10)
return true;
else
return false;
};
$('#id_mindstate, #id_sleep, #id_stress, #id_fatigue, #id_muscle_soreness').on('change', function(){
test = check_form_values();
if(test) {
$("#note_info").show();
$("#span_info_required").show();
} else {
$("#note_info").hide();
$("#span_info_required").hide();
function is_informations_needed()
{
var test = is_value_lower($('#id_mindstate').val());
test = test || is_value_lower($('#id_sleep').val());
test = test || is_value_upper($('#id_stress').val());
test = test || is_value_upper($('#id_fatigue').val());
test = test || is_value_upper($('#id_muscle_soreness').val());
return test
}
function is_value_lower(value)
{
if(value != '')
if(value <= 5)
return true;
else
return false;
};
function is_value_upper(value)
{
if(value != '')
if(value >= 5)
return true;
else
return false;
};
$('#id_mindstate, #id_sleep, #id_stress, #id_fatigue, #id_muscle_soreness').on('change', function(){
informations_needed = is_informations_needed();
if(informations_needed) {
$("#note_info").show();
$("#span_info_required").show();
$("#div_submit").hide();
} else {
$("#note_info").hide();
$("#span_info_required").hide();
$("#div_submit").show();
}
});
$('#id_informations').on('keyup', function(){
test = is_informations_needed();
test = test && is_information_field_too_short()
if(test) {
$("#note_info").show();
$("#div_submit").hide();
} else {
$("#note_info").hide();
$("#div_submit").show();
}
});
const csrf_token = "{{ csrf_token|escapejs }}";
const event_lookup = "{% url 'event_lookup' %}";
const gymnast_lookup = "{% url 'gymnast_lookup' %}";
});
</script>
{% if request.session.template == 0 %}
<script src="{% static "js/template_users/gymnast_autocomplete_black.js" %}"></script>
<script src="{% static "js/template_users/event_autocomplete_black.js" %}"></script>
{% else %}
<script src="{% static "js/template_users/gymnast_autocomplete.js" %}"></script>
<script src="{% static "js/template_users/event_autocomplete.js" %}"></script>
{% endif %}
$('#id_informations').on("keyup", function(){
test = check_form_values();
test = test && are_informations_too_short()
if(test)
$("#note_info").show();
else
$("#note_info").hide();
});
const csrf_token = "{{ csrf_token|escapejs }}";
const gymnast_lookup = "{% url 'gymnast_lookup' %}";
const event_lookup = "{% url 'event_lookup' %}";
});
</script>
{% if request.session.template == 0 %}
<script src="{% static "js/template_users/gymnast_autocomplete_black.js" %}"></script>
<script src="{% static "js/template_users/event_autocomplete_black.js" %}"></script>
{% else %}
<script src="{% static "js/template_users/gymnast_autocomplete.js" %}"></script>
<script src="{% static "js/template_users/event_autocomplete.js" %}"></script>
{% endif %}
{% endblock %}

View File

@ -1,5 +1,6 @@
{% extends "listing.html" %}
{% load has_group %}
{% load static %}
{% block datacontent %}
<div class="row justify-content-center">
@ -8,87 +9,153 @@
<div class="card-header row">
<div class="col-10 pr-0">
<h4 class="">
{% if gymnast %}<i>{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}<a href="{% url 'gymnast_details_tab' gymnast.id 'physiological' %}"><i>{% endif %}{{ gymnast }}</i></a>'s {% endif %} Well being list
{% if gymnast %}
{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}
<a href="{% url 'gymnast_details_tab' gymnast.id 'physiological' %}">
{% endif %}
{{ gymnast }}{% if gymnast.id in request.session.available_gymnast or request.user.is_superuser %}</a>{% endif %}'s{% endif %} Well beings
</h4>
</div>
<div class="col-2 ml-auto pl-0">
<div class="text-right">
{% if request.user|has_group:"trainer" %}
<a href="{% if gymnast %}{% url 'wellbeing_create_for_gymnast' gymnast.id %}{% else %}{% url 'wellbeing_create' %}{% endif %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fas fa-plus"></i>
</button>
</a>
<h3 class="mb-0">
<a href="{% if gymnast %}{% url 'wellbeing_create_for_gymnast' gymnast.id %}{% else %}{% url 'wellbeing_create' %}{% endif %}">
<i class="fas fa-plus text-warning"></i>
</a>
</h3>
{% endif %}
</div>
</div>
</div>
<div class="card-body">
{% if wellbeing_list %}
<table class="table tablesorter table-striped mb-0" data-sort="table" id="mindstate_table">
<thead>
<tr>
<th></th>
<th class="header text-left">Date</th>
{% if not gymnast %}
<th class="header text-left">Gymnast</th>
{% endif %}
<th class="header text-center">Mindstate</th>
<th class="header text-center">Sleep</th>
<th class="header text-center">Stress</th>
<th class="header text-center">Fatigue</th>
<th class="header text-center">Muscle soreness</th>
</tr>
</thead>
<tbody>
{% for wellbeing in wellbeing_list %}
<tr>
<td>
<a href="{% url 'wellbeing_update' wellbeing.id %}">
<span class="tim-icons icon-pencil text-warning"></span>
</a>
</td>
<td class="text-left">
{% if wellbeing.gymnast.id in request.session.available_gymnast or request.user.is_superuser %}<a href="{% url 'wellbeing_details' wellbeing.id %}">{% endif %}{{ wellbeing.date | date:"j-n-Y" }}</a>
</td>
{% if not gymnast %}
<td class="text-left">
{% if wellbeing.gymnast.id in request.session.available_gymnast or request.user.is_superuser %}<a href="{% url 'gymnast_details_tab' wellbeing.gymnast.id 'physiological' %}">{% endif %}
{{ wellbeing.gymnast }}
</a>
</td>
{% endif %}
<td class="text-right">
{% if wellbeing.mindstate < 5%}<b><span class="text-danger">{% endif %}
{{ wellbeing.mindstate }}
{% if wellbeing.mindstate < 5%}</b></span>{% endif %}
</td>
<td class="text-right">
{% if wellbeing.sleep < 5%}<b><span class="text-danger">{% endif %}
{{ wellbeing.sleep }}
{% if wellbeing.sleep < 5%}</b></span>{% endif %}
</td>
<td class="text-right">
{% if wellbeing.stress > 5%}<b><span class="text-danger">{% endif %}
{{ wellbeing.stress }}
{% if wellbeing.stress > 5%}</b></span>{% endif %}
</td>
<td class="text-right">
{% if wellbeing.fatigue > 5%}<b><span class="text-danger">{% endif %}
{{ wellbeing.fatigue }}
{% if wellbeing.fatigue > 5%}</b></span>{% endif %}
</td>
<td class="text-right">
{% if wellbeing.muscle_soreness > 5%}<b><span class="text-danger">{% endif %}
{{ wellbeing.muscle_soreness }}
{% if wellbeing.muscle_soreness > 5%}</b></span>{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="card-body pt-0">
{% if gymnast %}
<div class="row">
<div class="col-md-6">
<table class="table tablesorter table-striped mb-0" data-sort="table" id="mindstate_table">
<thead>
<tr>
<th></th>
<th class="header text-left">Date</th>
<th class="header text-center">Mindstate</th>
<th class="header text-center">Sleep</th>
<th class="header text-center">Stress</th>
<th class="header text-center">Fatigue</th>
<th class="header text-center">M. soreness</th>
</tr>
</thead>
<tbody>
{% for wellbeing in wellbeing_list %}
<tr>
<td>
<a href="{% url 'wellbeing_update' wellbeing.id %}">
<span class="tim-icons icon-pencil text-warning"></span>
</a>
</td>
<td class="text-left">
{% if wellbeing.gymnast.id in request.session.available_gymnast or request.user.is_superuser %}<a href="{% url 'wellbeing_details' wellbeing.id %}">{% endif %}{{ wellbeing.date | date:"j-n-Y" }}</a>
</td>
<td class="text-center">
{% if wellbeing.mindstate < 5%}<b><span class="text-danger">{% endif %}
{{ wellbeing.mindstate }}
{% if wellbeing.mindstate < 5%}</b></span>{% endif %}
</td>
<td class="text-center">
{% if wellbeing.sleep < 5%}<b><span class="text-danger">{% endif %}
{{ wellbeing.sleep }}
{% if wellbeing.sleep < 5%}</b></span>{% endif %}
</td>
<td class="text-center">
{% if wellbeing.stress > 5%}<b><span class="text-danger">{% endif %}
{{ wellbeing.stress }}
{% if wellbeing.stress > 5%}</b></span>{% endif %}
</td>
<td class="text-center">
{% if wellbeing.fatigue > 5%}<b><span class="text-danger">{% endif %}
{{ wellbeing.fatigue }}
{% if wellbeing.fatigue > 5%}</b></span>{% endif %}
</td>
<td class="text-center">
{% if wellbeing.muscle_soreness > 5%}<b><span class="text-danger">{% endif %}
{{ wellbeing.muscle_soreness }}
{% if wellbeing.muscle_soreness > 5%}</b></span>{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="col-md-6 pl-0 pr-0 pt-3">
<canvas id="chart_wellbeing" class="chartjs" width="100%">Your browser doesn't support canvas</canvas>
</div>
</div>
{% else %}
<p class="text-muted">There are no well being corresponding to your criterias</p>
{% if wellbeing_list %}
<table class="table tablesorter table-striped mb-0" data-sort="table" id="mindstate_table">
<thead>
<tr>
<th></th>
<th class="header text-left">Date</th>
{% if not gymnast %}
<th class="header text-left">Gymnast</th>
{% endif %}
<th class="header text-center">Mindstate</th>
<th class="header text-center">Sleep</th>
<th class="header text-center">Stress</th>
<th class="header text-center">Fatigue</th>
<th class="header text-center">Muscle soreness</th>
</tr>
</thead>
<tbody>
{% for wellbeing in wellbeing_list %}
<tr>
<td>
<a href="{% url 'wellbeing_update' wellbeing.id %}">
<span class="tim-icons icon-pencil text-warning"></span>
</a>
</td>
<td class="text-left">
{% if wellbeing.gymnast.id in request.session.available_gymnast or request.user.is_superuser %}<a href="{% url 'wellbeing_details' wellbeing.id %}">{% endif %}{{ wellbeing.date | date:"j-n-Y" }}</a>
</td>
{% if not gymnast %}
<td class="text-left">
{% if wellbeing.gymnast.id in request.session.available_gymnast or request.user.is_superuser %}<a href="{% url 'gymnast_details_tab' wellbeing.gymnast.id 'physiological' %}">{% endif %}
{{ wellbeing.gymnast }}
</a>
</td>
{% endif %}
<td class="text-right">
{% if wellbeing.mindstate < 5%}<b><span class="text-danger">{% endif %}
{{ wellbeing.mindstate }}
{% if wellbeing.mindstate < 5%}</b></span>{% endif %}
</td>
<td class="text-right">
{% if wellbeing.sleep < 5%}<b><span class="text-danger">{% endif %}
{{ wellbeing.sleep }}
{% if wellbeing.sleep < 5%}</b></span>{% endif %}
</td>
<td class="text-right">
{% if wellbeing.stress > 5%}<b><span class="text-danger">{% endif %}
{{ wellbeing.stress }}
{% if wellbeing.stress > 5%}</b></span>{% endif %}
</td>
<td class="text-right">
{% if wellbeing.fatigue > 5%}<b><span class="text-danger">{% endif %}
{{ wellbeing.fatigue }}
{% if wellbeing.fatigue > 5%}</b></span>{% endif %}
</td>
<td class="text-right">
{% if wellbeing.muscle_soreness > 5%}<b><span class="text-danger">{% endif %}
{{ wellbeing.muscle_soreness }}
{% if wellbeing.muscle_soreness > 5%}</b></span>{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p class="text-muted">There are no well being corresponding to your criterias</p>
{% endif %}
{% endif %}
</div>
</div>
@ -97,13 +164,14 @@
{% endblock %}
{% block footerscript %}
<script src="{% static "js/template_users/chart_gradient_color.js" %}"></script>
<script type="text/javascript">
$(document).ready(function () {
$('[data-sort="table"]').tablesorter({
headers: {
0: { sorter: false },
},
dateFormat: "uk",
dateFormat : "ddmmyyyy",
sortList: [[1, 1]]
});
@ -116,5 +184,172 @@
"bInfo" : false,
});
});
{% if wellbeing_list %}
var timeFormat = 'DD-M-YYYY';
var ctx = document.getElementById("chart_wellbeing").getContext("2d");
var border_color_pink = 'rgb(255, 99, 132)';
var gradient_stroke_pink = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_pink.addColorStop(1, 'rgba(255, 99, 132, 0.4)');
gradient_stroke_pink.addColorStop(0.75, 'rgba(255, 99, 132, 0.3)');
gradient_stroke_pink.addColorStop(0.5, 'rgba(255, 99, 132, 0.2)');
gradient_stroke_pink.addColorStop(0.25, 'rgba(255, 99, 132, 0)');
var border_color_orange = 'rgb(255, 159, 64)';
var gradient_stroke_orange = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_orange.addColorStop(1, 'rgba(255, 159, 64, 0.4)');
gradient_stroke_orange.addColorStop(0.75, 'rgba(255, 159, 64, 0.3)');
gradient_stroke_orange.addColorStop(0.5, 'rgba(255, 159, 64, 0.2)');
gradient_stroke_orange.addColorStop(0.25, 'rgba(255, 159, 64, 0)');
var border_color_green = 'rgb(75, 192, 192)';
var gradient_stroke_green = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_green.addColorStop(1, 'rgba(75, 192, 192, 0.4)');
gradient_stroke_green.addColorStop(0.75, 'rgba(75, 192, 192, 0.3)');
gradient_stroke_green.addColorStop(0.5, 'rgba(75, 192, 192, 0.2)');
gradient_stroke_green.addColorStop(0.25, 'rgba(75, 192, 192, 0)');
var border_color_blue = 'rgb(54, 162, 235)';
var gradient_stroke_blue = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_blue.addColorStop(1, 'rgba(54, 162, 235, 0.4)');
gradient_stroke_blue.addColorStop(0.75, 'rgba(54, 162, 235, 0.3)');
gradient_stroke_blue.addColorStop(0.5, 'rgba(54, 162, 235, 0.2)');
gradient_stroke_blue.addColorStop(0.25, 'rgba(54, 162, 235, 0)');
var border_color_yellow = 'rgb(255, 205, 86)';
var gradient_stroke_yellow = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_yellow.addColorStop(1, 'rgba(255, 205, 86, 0.4)');
gradient_stroke_yellow.addColorStop(0.75, 'rgba(255, 205, 86, 0.3)');
gradient_stroke_yellow.addColorStop(0.5, 'rgba(255, 205, 86, 0.2)');
gradient_stroke_yellow.addColorStop(0.25, 'rgba(255, 205, 86, 0)');
var mindstate_values = [
{% for wellbeing in wellbeing_list %}
{
x: '{{ wellbeing.date | date:"d-m-Y" }}',
y: '{{ wellbeing.mindstate }}'
},
{% endfor %}
];
var sleep_values = [
{% for wellbeing in wellbeing_list %}
{
x: '{{ wellbeing.date | date:"d-m-Y" }}',
y: '{{ wellbeing.sleep }}'
},
{% endfor %}
];
var stress_values = [
{% for wellbeing in wellbeing_list %}
{
x: '{{ wellbeing.date | date:"d-m-Y" }}',
y: '{{ wellbeing.stress }}'
},
{% endfor %}
];
var fatigue_values = [
{% for wellbeing in wellbeing_list %}
{
x: '{{ wellbeing.date | date:"d-m-Y" }}',
y: '{{ wellbeing.fatigue }}'
},
{% endfor %}
];
var muscle_soreness_values = [
{% for wellbeing in wellbeing_list %}
{
x: '{{ wellbeing.date | date:"d-m-Y" }}',
y: '{{ wellbeing.muscle_soreness }}'
},
{% endfor %}
];
var wellbeing_data = {
datasets: [
{
label: 'Mindstate',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_pink,
borderColor: border_color_pink,
pointBackgroundColor: border_color_pink,
fill: true,
data: mindstate_values,
},
{
label: 'Sleep',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_orange,
borderColor: border_color_orange,
pointBackgroundColor: border_color_orange,
fill: true,
data: sleep_values,
},
{
label: 'Stress',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_green,
borderColor: border_color_green,
pointBackgroundColor: border_color_green,
fill: true,
data: stress_values,
},
{
label: 'Fatigue',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_blue,
borderColor: border_color_blue,
pointBackgroundColor: border_color_blue,
fill: true,
data: fatigue_values,
},
{
label: 'Muscle',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_yellow,
borderColor: border_color_yellow,
pointBackgroundColor: border_color_yellow,
fill: true,
data: muscle_soreness_values,
},
],
};
new Chart(ctx, {
type: 'line',
data: wellbeing_data,
options: {
scales: {
x: {
type: 'time',
display: true,
scaleLabel: {
display: true,
labelString: 'Date',
ticks: {
autoSkip: true,
source: 'data',
},
},
time: {
parser: timeFormat,
tooltipFormat: 'LL',
round: 'day',
},
},
},
plugins: {
legend: {
display: true,
position: 'bottom',
}
}
},
});
{% endif %}
</script>
{% endblock %}

View File

@ -17,6 +17,7 @@ from jarvis.followup.models import (
SeasonInformation,
CompetitivePointsStats,
)
from datetime import date
from jarvis.followup.models import (
CHRONO_TYPE_CHOICE,
@ -36,24 +37,27 @@ class TestModels(TestCase):
Injury.objects.create(
gymnast=gymnast, location=0, injury_type=0, body_side=0, mechanism=0
)
WellBeing.objects.create(gymnast=gymnast, mindstate=9, sleep=8, stress=7, fatigue=6, muscle_soreness=5)
def test_chrono_to_string(self):
def test_chrono_str(self):
"""Test the __str__ method to ensure it returns the correct string representation of a Chrono instance."""
gymnast = Gymnast.objects.get(last_name="Pauchou")
chrono = Chrono.objects.get(gymnast=gymnast)
today = pendulum.now().to_date_string()
print(today)
self.assertEqual(str(chrono), f"Fred Pauchou - 13.000 ({today} - 0)")
# def test_chrono_timeline_representation(self):
# gymnast = Gymnast.objects.get(last_name="Pauchou")
# chrono = Chrono.objects.get(gymnast=gymnast)
# today = pendulum.now().date()
# self.assertEqual(
# chrono.timeline_representation,
# f"<li>{today.to_date_string()} - New personel best {CHRONO_TYPE_CHOICE[chrono.chrono_type][1]}: 15.000' (13.000')</li>", # pylint: disable=line-too-long
# )
expected_str = f"{gymnast} - 13.000 ({today} - 0)"
self.assertEqual(str(chrono), expected_str, "The __str__ method does not return the expected string.")
def test_compute_tof(self):
def test_chrono_timeline_representation(self):
"""Test the timeline_representation method to ensure it returns the correct HTML string."""
gymnast = Gymnast.objects.get(last_name="Pauchou")
chrono = Chrono.objects.get(gymnast=gymnast)
today = pendulum.now().date()
expected_html = f"<li>{today:%d %b %Y} - New personel best 10 |: 15.000' (13.000')</li>"
self.assertEqual(chrono.timeline_representation(), expected_html, "The timeline_representation method does not return the expected HTML string.")
def test_chrono_compute_tof(self):
res = Chrono.compute_tof(15)
self.assertEqual(res, 13)
@ -62,3 +66,42 @@ class TestModels(TestCase):
injury = Injury.objects.get(gymnast=gymnast)
today = pendulum.now().date()
self.assertEqual(str(injury), f"Fred Pauchou ({today})")
def test_wellbeing_get_inversed_stress(self):
"""Test the get_inversed_stress method to ensure it correctly calculates the inversed stress."""
gymnast = Gymnast.objects.get(last_name="Pauchou")
well_being = WellBeing.objects.get(gymnast=gymnast)
inversed_stress = well_being.get_inversed_stress
self.assertEqual(inversed_stress, 3, "The inversed stress should be 3 for a stress value of 7")
def test_wellbeing_get_inversed_fatigue(self):
"""Test the get_inversed_fatigue property to ensure it correctly calculates the inversed fatigue."""
gymnast = Gymnast.objects.get(last_name="Pauchou")
well_being = WellBeing.objects.get(gymnast=gymnast)
inversed_fatigue = well_being.get_inversed_fatigue
self.assertEqual(inversed_fatigue, 4, "The inversed fatigue should be 4 for a fatigue value of 6")
def test_wellbeing_get_inversed_muscle_soreness(self):
"""Test the get_inversed_muscle_soreness property to ensure it correctly calculates the inversed muscle soreness."""
gymnast = Gymnast.objects.get(last_name="Pauchou")
well_being = WellBeing.objects.get(gymnast=gymnast)
inversed_muscle_soreness = well_being.get_inversed_muscle_soreness
self.assertEqual(inversed_muscle_soreness, 5, "The inversed muscle soreness should be 5 for a muscle soreness value of 5")
def test_heightweight_bmi_calculation(self):
"""Test the bmi method to ensure it correctly calculates the BMI."""
gymnast = Gymnast.objects.get(last_name="Pauchou")
heightweight = HeightWeight(
gymnast=gymnast,
height=180,
weight=75
)
heightweight.save()
expected_bmi = 75 / (1.8 ** 2)
self.assertAlmostEqual(heightweight.bmi, expected_bmi, places=2, msg="The bmi method does not return the expected BMI.")

View File

@ -65,7 +65,7 @@ class URLTestCase(TestCase):
self.assertEqual(
resolve("/follow-up/injury/search/").view_name, "injury_search"
)
self.assertEqual(resolve("/follow-up/injury/").view_name, "injuries_list")
self.assertEqual(resolve("/follow-up/injury/").view_name, "injury_list")
self.assertEqual(resolve("/follow-up/injury/add/").view_name, "injury_create")
self.assertEqual(
resolve("/follow-up/injury/add/1/").view_name,

View File

@ -0,0 +1,62 @@
from django.test import TestCase, Client
from django.urls import reverse
from jarvis.people.models import Gymnast
from jarvis.followup.models import Chrono, ChronoDetails
from django.contrib.auth.models import User
class ChronoViewTests(TestCase):
def setUp(self):
# Create a user for authentication
self.user = User.objects.create_user(username='testuser', password='12345')
self.client = Client()
self.client.login(username='testuser', password='12345')
# Create a Chrono and ChronoDetails
self.gymnast = Gymnast.objects.create(
last_name="Pauchou", first_name="Fred", birthdate="1987-07-03", gender=0
)
self.chrono = Chrono.objects.create(
gymnast=self.gymnast, chrono_type=0, score_type=0, score=15, tof=13
)
def test_remove_jump_chrono_value_success(self):
"""Test removing a chrono detail successfully."""
url = reverse('remove_jump_chrono_value') # Ensure you have named your URL in urls.py
self.chrono_detail = ChronoDetails.objects.create(chrono=self.chrono, order=1, value=9.5)
response = self.client.post(url, {'chrono_id': self.chrono.id, 'order': 1})
self.assertEqual(response.status_code, 200)
self.assertFalse(ChronoDetails.objects.filter(id=self.chrono_detail.id).exists())
def test_remove_jump_chrono_value_not_found(self):
"""Test removing a non-existing chrono detail."""
url = reverse('remove_jump_chrono_value') # Ensure you have named your URL in urls.py
self.chrono_detail = ChronoDetails.objects.create(chrono=self.chrono, order=1, value=9.5)
response = self.client.post(url, {'chrono_id': self.chrono.id, 'order': 999})
self.assertEqual(response.status_code, 404)
# def test_remove_jump_chrono_value_missing_parameters(self):
# """Test the response when required parameters are missing."""
# url = reverse('remove_jump_chrono_value')
# self.chrono_detail = ChronoDetails.objects.create(chrono=self.chrono, order=1, value=9.5)
# response = self.client.post(url, {'chrono_id': self.chrono.id}) # 'order' is missing
# self.assertEqual(response.status_code, 400)
def test_add_jump_chrono_value_success(self):
"""Test adding a new chrono detail successfully."""
url = reverse('add_jump_chrono_value')
response = self.client.post(url, {'chrono_id': self.chrono.id, 'order': 1, 'value': 9.5})
self.assertEqual(response.status_code, 201)
self.assertTrue(ChronoDetails.objects.filter(chrono=self.chrono, order=1, value=9.5).exists())
def test_add_jump_chrono_value_conflict(self):
"""Test adding a chrono detail that already exists."""
ChronoDetails.objects.create(chrono=self.chrono, order=1, value=9.5)
url = reverse('add_jump_chrono_value')
response = self.client.post(url, {'chrono_id': self.chrono.id, 'order': 1, 'value': 9.5})
self.assertEqual(response.status_code, 409)
# def test_add_jump_chrono_value_missing_parameters(self):
# """Test the response when required parameters are missing."""
# url = reverse('add_jump_chrono_value')
# response = self.client.post(url, {'chrono_id': self.chrono.id, 'order': 1}) # 'value' is missing
# self.assertEqual(response.status_code, 400)

View File

@ -165,8 +165,12 @@ urlpatterns = [
#
#
# ACCIDENT
path(r"injury/search/", views_physiological.injuries_listing, name="injury_search"),
path(r"injury/", views_physiological.injuries_listing, name="injuries_list"),
path(r"injury/search/", views_physiological.injury_listing, name="injury_search"),
path(r"injury/", views_physiological.injury_listing, name="injury_list"),
path(
r"injury/gymnast/<int:gymnast_id>/",
views_physiological.injury_listing,
name="injury_list_for_gymnast"),
path(
r"injury/add/",
views_physiological.injury_create_or_update,
@ -309,6 +313,11 @@ urlpatterns = [
path(
r"season-information/add/<int:gymnast_id>/",
views.season_information_create_or_update,
name="add_season_information_for_gymnast",
name="season_information_create_for_gymnast",
),
path(
r"season-information/details/<int:season_information_id>/",
views.season_information_details,
name="season_information_details",
),
]

View File

@ -55,6 +55,7 @@ def note_listing(request, gymnast_id=None):
gymnast = None
if gymnast_id and (
request.user.is_superuser
or request.user.gymnast.id == gymnast_id
or (
request.session.has_key("available_gymnast")
and gymnast_id in request.session["available_gymnast"]
@ -147,16 +148,20 @@ def note_create_or_update(request, note_id=None, gymnast_id=None):
url = request.build_absolute_uri(
reverse("gymnast_details_tab", args=(new_note.gymnast.id, "event"))
)
receivers = [
new_note.gymnast.user.email,
new_note.gymnast.email_trainer,
]
receivers = []
if new_note.gymnast.user.email:
receivers.append(new_note.gymnast.user.email)
if new_note.gymnast.email_trainer:
receivers.append(new_note.gymnast.email_trainer)
title = f"{new_note.gymnast} : Nouvelle note"
body = f"""<p>Bonjour,</p><p>Une nouvelle note vous a été envoyée. Vous pouvez la consulter en cliquant <a href='{url}'>ici</a>.</p>"""
body = f"""<p>Bonjour {new_note.gymnast.first_name},</p><p>Une nouvelle note vous a été laissée par un de vos coaches. Vous pouvez la consulter en cliquant <a href='{url}'>ici</a>.</p>"""
send_mail(
title,
"Une nouvelle note vous a été envoyée",
"Une nouvelle note vous a été laissée.",
settings.EMAIL_HOST_USER,
receivers,
fail_silently=False,
@ -203,9 +208,9 @@ def gymnast_learn_skill(request):
return HttpResponse(status=200)
if gymnast_id:
print("Error : can not link Gymnast and skill. Missing Skill_ID.")
print("Error : can not link Gymnast and skill. Missing skill_id.")
else:
print("Error : can not link Gymnast and skill. Missing Gymnast_ID.")
print("Error : can not link Gymnast and skill. Missing gymnast_id.")
return HttpResponse(status=500)
@ -392,6 +397,7 @@ def score_listing(request, gymnast_id=None):
gymnast = None
if gymnast_id and (
request.user.is_superuser
or request.user.gymnast.id == gymnast_id
or (
request.session.has_key("available_gymnast")
and gymnast_id in request.session["available_gymnast"]
@ -424,6 +430,7 @@ def routine_done_listing(request, gymnast_id=None):
gymnast = None
if gymnast_id and (
request.user.is_superuser
or request.user.gymnast.id == gymnast_id
or (
request.session.has_key("available_gymnast")
and gymnast_id in request.session["available_gymnast"]
@ -703,10 +710,7 @@ def season_information_create_or_update(
)
return HttpResponseRedirect(
reverse(
"gymnast_details",
args=(form.cleaned_data["gymnast"].id,),
)
reverse("gymnast_details_tab", args=(season_information.gymnast.id, "season_informations"))
)
return render(request, "seasoninformations/create.html", {"form": form})
@ -744,3 +748,17 @@ def season_information_listing(request, gymnast_id=None):
context = {"season_information_list": season_information_list, "gymnast": gymnast}
return render(request, "seasoninformations/list.html", context)
@login_required
@require_http_methods(["GET"])
def season_information_details(request, season_information_id=None):
"""Détails des informations de saison pour un gymnaste.
Args:
season_information_id (int) identifiant d'un gymnaste
"""
season_information = get_object_or_404(SeasonInformation, pk=season_information_id)
context = {"season_information": season_information}
return render(request, "seasoninformations/details.html", context)

View File

@ -42,33 +42,35 @@ def jump_chrono_details(request, chrono_id):
Args:
chrono_id (int) identifiant chrono
QTF : Est-ce que je ne devrais pas faire un prefetch_related sur mon objet chrono pour
optimiser mon affichage ?
chrono = Chrono.object.get(pk=chrono_id).prefetch_related('chrono_details') ?
"""
chrono = get_object_or_404(Chrono, pk=chrono_id)
# Using prefetch_related to optimize database access for related details
chrono = get_object_or_404(Chrono.objects.prefetch_related('details'), pk=chrono_id)
# Access control for non-superusers
if not request.user.is_superuser and (
request.session.has_key("available_gymnast")
and chrono.gymnast.id not in request.session["available_gymnast"]
request.session.has_key("available_gymnast") and
chrono.gymnast.id not in request.session["available_gymnast"]
):
return chrono_listing(request)
sum_value = chrono.details.all().aggregate(total=Sum("value"))
# Aggregate values from details
details = chrono.details.all()
sum_value = details.aggregate(total=Sum("value"))['total']
mean_value = details.aggregate(mean=Avg("value"))['mean']
min_value = details.aggregate(min=Min("value"))['min']
max_value = details.aggregate(max=Max("value"))['max']
if chrono.score != sum_value["total"]:
chrono.score = sum_value["total"]
# Update chrono score if different
if chrono.score != sum_value:
chrono.score = sum_value
if chrono.score_type == 0:
chrono.tof = Chrono.compute_tof(sum_value["total"])
chrono.tof = Chrono.compute_tof(sum_value)
chrono.save()
mean_value = chrono.details.all().aggregate(mean=Avg("value"))["mean"]
tmp_min_value = chrono.details.all().aggregate(min=Min("value"))["min"]
tmp_max_value = chrono.details.all().aggregate(max=Max("value"))["max"]
chart_min_value = mean_value - (tmp_min_value / 20)
chart_max_value = mean_value - (tmp_max_value / 20)
# Calculate chart values
chart_min_value = mean_value - (min_value / 20)
chart_max_value = mean_value + (max_value / 20)
context = {
"chrono": chrono,
@ -79,6 +81,38 @@ def jump_chrono_details(request, chrono_id):
return render(request, "chronos/details.html", context)
# @login_required
# @require_http_methods(["GET"])
# def average_jump_chrono_details_for_gymnast(
# request, gymnast_id, routine_type=1, season=None, week_number=None
# ):
# """Retrieves all the chronos for a gymnast and a type of routine within a specific season and week.
# Args:
# gymnast_id (int) Identifiant d'un gymnaste
# routine_type (int) Type de série (cf. jarvis/followup/models.py > ROUTINE_CHOICE)
# season (string) Saison sous forme "xxxx-xxxy"
# week_number (int) numéro de semaine (1, …, 52)
# """
# if season is None or week_number is None:
# today = pendulum.now().date()
# season, week_number = from_date_to_week_number(today)
# else:
# # Ensure week_number is within the valid range
# week_number = max(1, min(week_number, 52))
# # Ensure season is properly formatted or converted
# season = Season(season).label if isinstance(season, str) else season
# return average_jump_chrono_details_for_season_and_week(
# request,
# gymnast_id,
# routine_type,
# season,
# week_number,
# )
@login_required
@require_http_methods(["GET"])
def average_jump_chrono_details_for_gymnast(
@ -109,40 +143,49 @@ def average_jump_chrono_details_for_gymnast(
)
@login_required
@require_http_methods(["POST"])
def remove_jump_chrono_value(request):
"""
Recoit trois informations permettant de supprimer le chrono d'un saut à un chrono.
Receives information to remove a jump time from a Chrono record.
"""
chrono_id = request.POST.get("chrono_id", None)
order = request.POST.get("order", None)
chrono_id = request.POST.get("chrono_id")
order = request.POST.get("order")
if not chrono_id or not order:
return HttpResponse(400, "Missing required parameters.")
chrono = get_object_or_404(Chrono, pk=chrono_id)
try:
ChronoDetails.objects.filter(chrono=chrono, order=order).delete()
except Exception:
return HttpResponse(409)
deleted, _ = ChronoDetails.objects.filter(chrono=chrono, order=order).delete()
return HttpResponse(200)
if deleted:
return HttpResponse(status=200)
return HttpResponse(status=404)
@login_required
@require_http_methods(["POST"])
def add_jump_chrono_value(request):
"""
Recoit trois informations permettant d'ajouter le chrono d'un saut à un chrono.
Receives three pieces of information to add the time of a jump to a <Chrono> record.
"""
chrono_id = request.POST.get("chrono_id", None)
order = request.POST.get("order", None)
value = request.POST.get("value", None)
chrono_id = request.POST.get("chrono_id")
order = request.POST.get("order")
value = request.POST.get("value")
if not chrono_id or not order or value is None:
return HttpResponse(400, "Missing required parameters.")
chrono = get_object_or_404(Chrono, pk=chrono_id)
row, created = ChronoDetails.objects.get_or_create(
chrono=chrono, order=order, value=value
chrono=chrono, order=order, defaults={'value': value}
)
if created:
return HttpResponse(200, (row, created)) # devrait être un 201
return HttpResponse(status=201)
return HttpResponse(400, (row, created))
return HttpResponse(status=409) # 409 Conflict
@login_required
@ -156,12 +199,10 @@ def jump_chrono_values_create_or_update(request, chrono_id):
"""
chrono = get_object_or_404(Chrono, pk=chrono_id)
jump_list = chrono.details.all()
number_of_jump = jump_list.count()
context = {
"chrono": chrono,
"jump_list": jump_list,
"number_of_jump": number_of_jump,
"jump_list": chrono.details.all(),
"number_of_jump": jump_list.count(),
"score_type": chrono.score_type,
}
return render(request, "chronos/add_details.html", context)
@ -235,15 +276,17 @@ def average_jump_chrono_details_between_two_date(
@require_http_methods(["GET"])
def get_chrono_detail_distinct_season(request, gymnast_id):
"""Récupère toutes les saisons pour lesquelles le gymnaste a des chronos détaillés.
"""Retrieves all distinct seasons for which the gymnast has detailed chronos.
Args:
gymnast_id (int) Identifiant d'un gymnaste
"""
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
get_object_or_404(Gymnast, pk=gymnast_id)
season_list = list(
gymnast.chronos.values_list("season", flat=True)
.distinct("season")
Chrono.objects.filter(gymnast_id=gymnast_id)
.values_list("season", flat=True)
.distinct()
.order_by("season")
)
return JsonResponse(season_list, safe=False)
@ -251,18 +294,18 @@ def get_chrono_detail_distinct_season(request, gymnast_id):
@require_http_methods(["GET"])
def get_chrono_detail_distinct_weeknumber_for_season(request, gymnast_id, season):
"""Récupère toutes les week_number pour lesquelles le gymnaste a des chronos détaillés au cours
d'une saison.
"""Retrieves all distinct week numbers for which the gymnast has detailed chronos during a specific season.
Args:
gymnast_id (int) Identifiant d'un gymnaste
season (string) Season
"""
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
get_object_or_404(Gymnast, pk=gymnast_id)
weeknumber_list = list(
gymnast.chronos.values_list("week_number", flat=True)
.filter(season=season)
.distinct("week_number")
Chrono.objects.filter(gymnast_id=gymnast_id, season=season)
.values_list("week_number", flat=True)
.distinct()
.order_by("week_number")
)
return JsonResponse(weeknumber_list, safe=False)
@ -272,27 +315,24 @@ def get_chrono_detail_distinct_weeknumber_for_season(request, gymnast_id, season
def get_average_jump_chrono_details_for_season_and_week(
request, gymnast_id, routine_type, season, week_number
):
"""Récupère tout les chronos moyen par saut pour une saison & semaine d'un gymnaste
"""Retrieves average jump chronos per jump for a season and week for a gymnast.
Args:
gymnast_id (int) Identifiant d'un gymnaste
routine_type (int) Type de série (cf. jarvis/followup/models.py > ROUTINE_CHOICE)
gymnast_id (int) Gymnast ID
routine_type (int) Type of routine (cf. jarvis/followup/models.py > ROUTINE_CHOICE)
season (string) Season
week_number (int) Numero de la semaine
week_number (int) Number of week
"""
stat_values = ChronoDetails.objects.filter(
chrono__gymnast=gymnast_id,
chrono__chrono_type=routine_type,
chrono__season=season,
chrono__week_number=week_number,
).values("order").annotate(avg_score=Avg("value")).order_by("order")
stat_values = list(
ChronoDetails.objects.filter(
chrono__gymnast=gymnast_id,
chrono__chrono_type=routine_type,
chrono__season=season,
chrono__week_number=week_number,
)
.values("order")
.annotate(avg_score=Avg("value"))
.order_by("order")
)
return JsonResponse(stat_values, safe=False)
stat_values_list = list(stat_values)
return JsonResponse(stat_values_list, safe=False)
@login_required
@ -308,7 +348,6 @@ def average_jump_chrono_details_for_season_and_week(
season (string) Season
week_number (int) Numero de la semaine
"""
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
stat_values = (
@ -378,14 +417,32 @@ def chrono_listing(request, gymnast_id=None):
gymnast = None
if gymnast_id and (
request.user.is_superuser
or request.user.gymnast.id == gymnast_id
or (
request.session.has_key("available_gymnast")
and gymnast_id in request.session["available_gymnast"]
)
):
chrono_list = Chrono.objects.filter(gymnast=gymnast_id)
gymnast = Gymnast.objects.get(pk=gymnast_id)
chrono_list = Chrono.objects.filter(gymnast=gymnast_id).order_by("date")
base_queryset = chrono_list.values("date").annotate(score_avg=Avg("tof"))
context = {
"chrono_10c": base_queryset.filter(chrono_type=0),
"chrono_r1": base_queryset.filter(chrono_type=1),
"chrono_r2": base_queryset.filter(chrono_type=2),
"chrono_rf": base_queryset.filter(chrono_type=3),
}
personnal_best_10 = Chrono.objects.filter(gymnast=gymnast_id, chrono_type=0).order_by("-tof").first()
personnal_best_q1r1 = Chrono.objects.filter(gymnast=gymnast_id, chrono_type=1).order_by("-tof").first()
personnal_best_q1r2 = Chrono.objects.filter(gymnast=gymnast_id, chrono_type=2).order_by("-tof").first()
context["personnal_best_10"] = personnal_best_10
context["personnal_best_q1r1"] = personnal_best_q1r1
context["personnal_best_q1r2"] = personnal_best_q1r2
else:
context = {}
if request.user.is_superuser:
chrono_list = Chrono.objects.all()
else:
@ -393,7 +450,8 @@ def chrono_listing(request, gymnast_id=None):
gymnast__in=request.session["available_gymnast"]
)
context = {"chrono_list": chrono_list, "gymnast": gymnast}
context["chrono_list"] = chrono_list
context["gymnast"] = gymnast
return render(request, "chronos/list.html", context)
@ -466,7 +524,7 @@ def chrono_create_or_update(request, chrono_id=None, gymnast_id=None):
)
return HttpResponseRedirect(
reverse("gymnast_details_tab", args=(new_chrono.gymnast.id, "scores"))
reverse("chrono_list_for_gymnast", args=(new_chrono.gymnast.id,))
)
return render(request, "chronos/create.html", {"form": form})

View File

@ -73,6 +73,7 @@ def intensity_listing(request, gymnast_id=None):
gymnast = None
if gymnast_id and (
request.user.is_superuser
or request.user.gymnast.id == gymnast_id
or (
request.session.has_key("available_gymnast")
and gymnast_id in request.session["available_gymnast"]
@ -106,6 +107,8 @@ def intensity_details(request, intensity_id):
if not request.user.is_superuser and (
request.session.has_key("available_gymnast")
and intensity.gymnast.id not in request.session["available_gymnast"]
) and (
intensity.gymnast.id != request.user.gymnast.id
):
return intensity_listing(request)

View File

@ -34,7 +34,7 @@ from .email_vars import MAIL_HEADER, MAIL_FOOTER
@login_required
@require_http_methods(["GET"])
def injuries_listing(request, gymnast_id=None):
def injury_listing(request, gymnast_id=None):
"""
Récupère la liste des bessures.
Si c'est un gymnaste qui est connecté, il ne peut récupérer que la liste de ses blessures.
@ -51,16 +51,16 @@ def injuries_listing(request, gymnast_id=None):
)
):
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
injuries_list = Injury.objects.filter(gymnast=gymnast_id)
injury_list = Injury.objects.filter(gymnast=gymnast_id)
else:
if request.user.is_superuser:
injuries_list = Injury.objects.all()
injury_list = Injury.objects.all()
else:
injuries_list = Injury.objects.filter(
injury_list = Injury.objects.filter(
gymnast__in=request.session["available_gymnast"]
)
context = {"injuries_list": injuries_list, "gymnast": gymnast}
context = {"injury_list": injury_list, "gymnast": gymnast}
return render(request, "injuries/list.html", context)
@ -152,7 +152,7 @@ def injury_details(request, injury_id):
request.session.has_key("available_gymnast")
and injury.gymnast.id not in request.session["available_gymnast"]
):
return injuries_listing(request)
return injury_listing(request)
return render(request, "injuries/details.html", {"injury": injury})
@ -170,12 +170,12 @@ def wellbeing_listing(request, gymnast_id=None):
gymnast = None
if gymnast_id and (
request.user.is_superuser
or request.user.gymnast.id == gymnast_id
or (
request.session.has_key("available_gymnast")
and gymnast_id in request.session["available_gymnast"]
)
):
# wellbeing_list = WellBeing.objects.filter(gymnast=gymnast_id)
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
wellbeing_list = gymnast.wellbeings.all()
else:
@ -316,8 +316,10 @@ def wellbeing_details(request, wellbeing_id):
if not request.user.is_superuser and (
request.session.has_key("available_gymnast")
and wellbeing.gymnast.id not in request.session["available_gymnast"]
) and (
wellbeing.gymnast.id != request.user.gymnast.id
):
return wellbeing_listing(request)
return HttpResponseRedirect(reverse("wellbeing_list"))
return render(request, "wellbeing/details.html", {"wellbeing": wellbeing})
@ -335,6 +337,7 @@ def heightweight_listing(request, gymnast_id=None):
gymnast = None
if gymnast_id and (
request.user.is_superuser
or request.user.gymnast.id == gymnast_id
or (
request.session.has_key("available_gymnast")
and gymnast_id in request.session["available_gymnast"]
@ -350,7 +353,7 @@ def heightweight_listing(request, gymnast_id=None):
gymnast__in=request.session["available_gymnast"]
)
context = {"heightweight_list": heightweight_list, "gymnast": gymnast}
context = {"height_weight_list": heightweight_list, "gymnast": gymnast}
return render(request, "heightweight/list.html", context)

View File

@ -16,7 +16,7 @@
<div class="col-8 col-sm-10 col-md-10 col-lg-10 col-xl-10">
{{ form.name }}
{% if form.name.errors %}
<span class="btn btn-sm btn-danger-outline">
<span class="btn btn-sm">
{% for error in form.name.errors %}{{ error }}{% endfor %}
</span>
{% endif %}
@ -26,7 +26,7 @@
<label for="id_name" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Address</label>
<div class="col-8 col-sm-6 col-md-6 col-lg-6 col-xl-6">
{{ form.address }}
{% if form.address.errors %}<span class="btn btn-sm btn-danger-outline">{% for error in form.address.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.address.errors %}<span class="btn btn-sm">{% for error in form.address.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row {% if form.postal.errors %}has-error has-feedback{% endif %}">
@ -35,11 +35,11 @@
<div class="row">
<div class="col-7 col-sm-5 col-md-5 col-lg-5 col-xl-3 pr-0">
{{ form.postal }}
{% if form.postal.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.postal.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.postal.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.postal.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
<div class="col-12 col-sm-7 col-md-7 col-lg-7 col-xl-9">
{{ form.city }}
{% if form.city.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.city.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.city.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.city.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
</div>
@ -58,11 +58,11 @@
<div class="row">
<div class="col-7 col-sm-5 col-md-5 col-lg-5 col-xl-3 pr-0">
{{ form.nbkm }}
{% if form.nbkm.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.nbkm.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.nbkm.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.nbkm.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
<div class="col-7 col-sm-5 col-md-5 col-lg-5 col-xl-3 pr-0">
{{ form.timing }}
{% if form.timing.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.timing.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.timing.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.timing.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
</div>
@ -71,7 +71,7 @@
<label for="id_name" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Is active</label>
<div class="col-8 col-sm-2 col-md-2 col-lg-2 col-xl-2">
{{ form.active }}
{% if form.active.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.active.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.active.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.active.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group text-center">

View File

@ -3,9 +3,9 @@
{% block datacontent %}
<div class="card mb-0">
<div class="card-header">
<h4 class=""> Club Listing</h4>
<h4 class="">Club Listing</h4>
</div>
<div class="card-body pb-0">
<div class="card-body pt-0 pb-0">
<div class="table-responsive pb-0">
{% if club_list %}
<table class="table tablesorter table-striped table-condensed" data-sort="table" id="club_table">
@ -41,7 +41,7 @@
headers: {
0: { sorter: false }, // disable first column
},
dateFormat: "uk",
dateFormat : "ddmmyyyy",
sortList: [[3,0], [1,0]]
});

View File

@ -16,7 +16,7 @@
<div class="col-8 col-sm-8 col-md-8 col-lg-8 col-xl-8">
{{ form.name }}
{% if form.name.errors %}
<span class="btn btn-sm btn-danger-outline">
<span class="btn btn-sm">
{% for error in form.name.errors %}{{ error }}{% endfor %}
</span>
{% endif %}
@ -26,7 +26,7 @@
<label for="id_name" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Address <span class="text-danger"><b>*</b></span></label>
<div class="col-8 col-sm-6 col-md-6 col-lg-6 col-xl-8">
{{ form.address }}
{% if form.address.errors %}<span class="btn btn-sm btn-danger-outline">{% for error in form.address.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.address.errors %}<span class="btn btn-sm">{% for error in form.address.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row {% if form.postal.errors %}has-error has-feedback{% endif %}">
@ -34,11 +34,11 @@
<div class="col-8 col-sm-6 col-md-6 col-lg-6 col-xl-8 row">
<div class="col-7 col-sm-5 col-md-5 col-lg-5 col-xl-4 pr-0">
{{ form.postal }}
{% if form.postal.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.postal.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.postal.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.postal.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
<div class="col-12 col-sm-7 col-md-7 col-lg-7 col-xl-8">
{{ form.city }}
{% if form.city.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.city.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.city.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.city.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
</div>
@ -55,7 +55,7 @@
<label for="id_name" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Is active</label>
<div class="col-8 col-sm-2 col-md-2 col-lg-2 col-xl-2">
{{ form.active }}
{% if form.active.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.active.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.active.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.active.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
{% endif %}

View File

@ -3,37 +3,35 @@
{% block datacontent %}
<div class="card mb-0">
<div class="card-header">
<div class="row">
<div class="col-2">
<h4 class=""> Places Listing</h4>
</div>
<div class="col-1 ml-auto">
<div class="text-right">
{% if request.user|has_group:"trainer" %}
<a href="{% url 'place_create' %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fas fa-plus"></i>
</button>
</a>
{% endif %}
</div>
<div class="card-header row">
<div class="col-10">
<h4 class=""> Places Listing</h4>
</div>
<div class="col-1 ml-auto">
<div class="text-right">
{% if request.user|has_group:"trainer" %}
<a href="{% url 'place_create' %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fas fa-plus"></i>
</button>
</a>
{% endif %}
</div>
</div>
</div>
<div class="card-body">
<div class="card-body pt-0 pb-0">
<div class="table-responsive pb-0">
{% if place_list %}
<table class="table tablesorter table-striped" data-sort="table" id="place_table">
<table class="table tablesorter table-condensed table-striped" data-sort="table" id="place_table">
<thead>
<tr>
{% if request.user|has_group:"trainer" %}
<th style="width: 3%"></th>
{% endif %}
<th class="header text-left" style="width: 27%">Name</th>
<th class="header text-left" style="width: 30%">Name</th>
<th class="header text-left" style="width: 35%">Address</th>
<th class="header text-center" style="width: 10%">Zip</th>
<th class="header text-left" style="width: 15%">City</th>
<th class="header text-center" style="width: 7%">Zip</th>
<th class="header text-center" style="width: 15%">City</th>
</tr>
</thead>
<tbody>
@ -48,8 +46,8 @@
{% endif %}
<td class="text-left"><a href="{% url 'place_details' place.id %}">{{ place.name }}</a></td>
<td class="text-left">{{ place.address }}</td>
<td class="text-left">{{ place.postal}}</td>
<td class="text-left">{{ place.city }}</td>
<td class="text-right">{{ place.postal}}</td>
<td class="text-right">{{ place.city }}</td>
</tr>
{% endfor %}
</tbody>
@ -74,7 +72,7 @@
{% else %}
sortList: [[2, 0], [0, 0]],
{% endif %}
dateFormat: "uk",
dateFormat : "ddmmyyyy",
});
$('#place_table').DataTable({

View File

@ -9,10 +9,8 @@ from django_admin_listfilter_dropdown.filters import (
from .models import (
TouchPosition,
Skill,
Passe,
Routine,
RoutineSkill,
TrainingProgram,
PrerequisiteClosure,
)
@ -192,59 +190,3 @@ class PrerequisiteClosureAdmin(admin.ModelAdmin):
("level", DropdownFilter),
("path", DropdownFilter),
)
@admin.register(Passe)
class PasseAdmin(admin.ModelAdmin):
model = Passe
fields = (
"label",
"educatives",
"regexp",
"number_of_skill",
"difficulty",
"informations",
)
list_display = ("label", "regexp", "number_of_skill", "difficulty")
list_filter = (
("number_of_skill", DropdownFilter),
("difficulty", DropdownFilter),
)
filter_horizontal = ("educatives",)
class Media:
js = (
"js/core/jquery-3.6.0.min.js",
"js/admin/passe.js",
)
@admin.register(TrainingProgram)
class TrainingProgramAdmin(admin.ModelAdmin):
model = TrainingProgram
fields = (
"gymnast",
"date",
"rank",
"passe",
"repetition",
"number_of_skill",
"difficulty",
# "score",
)
list_display = (
"date",
"gymnast",
"passe",
"rank",
"repetition",
"number_of_skill",
"difficulty",
)
list_filter = (
("gymnast", RelatedDropdownFilter),
("date", DropdownFilter),
)

View File

@ -1,15 +1,14 @@
import re
from django import forms
from django.core.exceptions import ValidationError
from django.contrib.admin.widgets import FilteredSelectMultiple
import re
from .models import (
Educative,
Skill,
Routine,
RoutineSkill,
Passe,
)
@ -72,89 +71,3 @@ class CombinationSkillForm(forms.ModelForm):
"skill": forms.HiddenInput(),
"rank": forms.NumberInput(),
}
class PasseForm(forms.ModelForm):
educatives = forms.ModelMultipleChoiceField(
required=False,
queryset=Educative.objects.all(),
widget=FilteredSelectMultiple("Educatives", is_stacked=False),
# widget=customFilteredSelectMultiple(verbose_name='test2',is_stacked=False)
)
class Media:
css = {
"all": ["admin/css/widgets.css"],
}
# Adding this javascript is crucial
js = ["/admin/jsi18n/"]
class Meta:
model = Passe
fields = ("label", "regexp", "educatives", "informations")
widgets = {
"label": forms.TextInput(
attrs={
"class": "form-control",
"placeholder": "Label (not mandatory)",
"maxlength": 30,
}
),
"regexp": forms.TextInput(
attrs={"class": "form-control", "placeholder": "[2-8]"}
),
"informations": forms.Textarea(
attrs={
"class": "form-control",
"placeholder": "Informations about the passe…", # pylint: disable=line-too-long
}
),
}
def clean_regexp(self):
"""Vérifie que la regexp entrée par l'utilisateur est valide."""
regexp = self.cleaned_data["regexp"]
if not Passe.is_valid_regexp(regexp):
raise ValidationError("Entered regexp not valid.")
return regexp
def clean(self):
"""Vérifie le contenu des champs `educatives` par rapport à la valeur de `regexp`. Si
`regexp` est définie par :
- valeurs de ROUTINE_TYPE_CHOICE il faut que Educatives soit VIDE
- avec [x-y]
- [x-y] " Educatives soit NON VIDE
- WC " il y ait 2+ Educatives
- x| " il y ait 1! Educatives
"""
cleaned_data = super().clean()
regexp = ["regexp"]
if regexp is not None:
arguments = regexp.split(" ")
educatives = cleaned_data["educatives"]
if Passe.is_valid_routine_type(arguments[0]) and educatives is not None:
raise ValidationError(
"Educatives must be empty with the entered Regexp."
)
if Passe.is_valid_subset(arguments[0]) and educatives is None:
raise ValidationError(
"Educatives can't be empty with the entered Regexp."
)
if re.match(r"[1-9]+\|", arguments[0]) and len(educatives) != 1:
raise ValidationError(
"One and only one Educatives allowed with the entered Regexp."
)
if arguments[0] == "WC" and (educatives is None or len(educatives) < 2):
raise ValidationError(
"At least two Educatives with the entered Regexp."
)
return cleaned_data

View File

@ -0,0 +1,31 @@
# Generated by Django 4.2 on 2024-03-25 11:58
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("objective", "0021_alter_passe_educatives"),
]
operations = [
migrations.AlterUniqueTogether(
name="trainingprogram",
unique_together=None,
),
migrations.RemoveField(
model_name="trainingprogram",
name="gymnast",
),
migrations.RemoveField(
model_name="trainingprogram",
name="passe",
),
migrations.DeleteModel(
name="Passe",
),
migrations.DeleteModel(
name="TrainingProgram",
),
]

View File

@ -331,6 +331,9 @@ class Routine(Educative):
# is_routine = False
is_competitive = True
print(self.is_competitive)
print(self.is_routine)
for skill_link in self.skill_links.all():
skill = skill_link.skill
@ -464,301 +467,3 @@ class RoutineSkill(models.Model):
def __str__(self):
return f"{self.rank} - {self.routine.short_label} : {self.skill.short_label}"
class Passe(Markdownizable):
"""Classe représentant les passages (à faire pendant un entraînement)."""
class Meta:
ordering = [
"label",
]
label = models.CharField(max_length=30)
educatives = models.ManyToManyField(
Educative, related_name="passes", blank=True, symmetrical=False
)
regexp = models.CharField(max_length=50, null=True, blank=True)
number_of_skill = models.PositiveSmallIntegerField(default=0)
difficulty = models.DecimalField(max_digits=4, decimal_places=1, default=0.0)
# TODO: number_of_skill doit être calculé correctement dans tous les cas.
def save(self, *args, **kwargs):
"""Sauve les informations de la personne et initialise les champs nettoyés.
On part du principe que self.regexp est correct.
"""
self.difficulty = 0
self.number_of_skill = 0
super().save(*args, **kwargs)
# print("Dans le save")
if self.educatives.count() == 0:
# print("educative is none")
present = False
operation_list = self.regexp.split(" ")
for item in ROUTINE_TYPE_CHOICE:
if item[1] == operation_list[0]:
present = True
break
if present and len(operation_list) == 2:
# print("present")
content = operation_list[1].replace("[", "").replace("]", "")
ranks = content.split("-")
if ranks[0] == "":
self.number_of_skill += int(ranks[1])
elif ranks[1] == "":
self.number_of_skill += (10 - int(ranks[0])) + 1
else:
self.number_of_skill += (int(ranks[1]) - int(ranks[0])) + 1
else:
self.number_of_skill += 10
else:
for educative in self.educatives.all():
is_skill = False
try:
educative = Routine.objects.get(pk=educative)
except Routine.DoesNotExist:
educative = Skill.objects.get(pk=educative)
is_skill = True
if is_skill:
self.difficulty += educative.difficulty
self.number_of_skill += 1
else:
if self.regexp is not None:
regexp = self.regexp.replace("[", "").replace("]", "")
position = regexp.find("-")
start = regexp[:position]
if start == "":
start = 0
else:
start = int(start)
end = regexp[position + 1 :]
if end == "":
end = educative.jumps.all().count()
else:
end = int(end)
self.number_of_skill += end - (start - 1)
list_of_skill = educative.skill_links.filter(
rank__gte=start, rank__lte=end
)
# .aggregate(total=Sum("value"))
tmp_difficulty = 0
for routine_skill in list_of_skill:
tmp_difficulty += routine_skill.skill.difficulty
self.difficulty += tmp_difficulty
else:
self.number_of_skill += educative.jumps.all().count()
self.difficulty += educative.difficulty
super().save(*args, **kwargs)
def __str__(self):
return f"{self.label} ({self.number_of_skill} | {self.difficulty})"
@staticmethod
def is_valid_regexp_one_arg(arg):
"""Vérifie une regexp avec un paramètre."""
if arg == "WC":
return True
if re.match(r"[1-9]+\|", arg):
return True
if not Passe.is_valid_dot(arg):
return False
value = arg.replace(".", "")
is_valid_routine = Passe.is_valid_routine_type(value)
if is_valid_routine:
return True
return Passe.is_valid_subset(arg)
@staticmethod
def is_valid_regexp_two_args(arg1, arg2):
"""Vérifie une regexp avec deux paramètres."""
if not Passe.is_valid_dot(arg1):
return False
value = arg1.replace(".", "")
is_valid_routine = Passe.is_valid_routine_type(value)
if is_valid_routine:
return Passe.is_valid_subset(arg2)
return False
@staticmethod
def is_valid_dot(pattern):
"""Reçoit une chaine de caratère et vérifie que si elle contient un point (.), il se trouve
soit à la première position soit à la dernière position.
"""
if len(re.findall("\.", pattern)) > 1:
return False
if re.search("\.", pattern):
last_place = len(pattern) - 1
if pattern[0] != "." and pattern[last_place] != ".":
return False
return True
@staticmethod
def is_valid_routine_type(routine_type):
"""Recoit une chaine de caractère et vérifie si elle est présente dans la liste
ROUTINE_TYPE_CHOICE (Educative vide !)
"""
is_valid = False
for item in ROUTINE_TYPE_CHOICE:
if item[1] == routine_type:
is_valid = True
break
return is_valid
@staticmethod
def is_valid_subset(subset):
"""Reçoit la description d'un subset sous forme de string et vérifie qu'elle est conforme.
Format attendu : [X-Y]
X ou Y peuvent être vide mais pas en même temps.
X est un entier >= 2
Y est un entier >= 2 OU Y > X si X est non vide
Exemples :
- [2-8] True
- [-5] True
- [3-] True
- [8-2] False
- [4--8] False
- [-] False
- [1-] False
- [-1] False
- [4] False
- [6-6] False
"""
if re.match(r"^\[(([2-9]+\-{1})|([2-9]+\-{1}[2-9]+)|(\-{1}[2-9]+))\]$", subset):
value = subset.replace("[", "").replace("]", "")
ranks = value.split("-")
if ranks[0] == "" or ranks[1] == "":
return True
if int(ranks[0]) < int(ranks[1]):
return True
return False
@staticmethod
def is_valid_regexp(regexp):
"""Vérifie le champ regexp
Exemples :
- Q1R1 True
- Q1R2 [2-8] True
- Q2R1 [-5] True
- SF [6-] True
- FS [3-7] True
- Q1R1. True
- .Q1R2 True
- Q1R1. [-4] True
- .Q1R2 [4-] True
- .FS [3-7] True
- [2-8] True
- [-5] True
- WC True
- 1| True
"""
argument_list = regexp.split(" ")
if len(argument_list) >= 3:
return False
if len(argument_list) == 2:
return Passe.is_valid_regexp_two_args(argument_list[0], argument_list[1])
else:
return Passe.is_valid_regexp_one_arg(argument_list[0])
return False
class TrainingProgram(Seasonisable, Markdownizable):
"""Classe représentant ?????
TODO:
- renommer (supprimer/remettre) TrainingProgram en TrainingPasse
- supprimer Seasonisable
- supprimer Markdownizable
- supprimer le champ Gymnast
- supprimer score
- supprimer rank ??? (--> dans la M2M)
- supprimer difficulty ??? (--> dans la M2M)
"""
class Meta:
verbose_name = "Training Program"
verbose_name_plural = "Trainings Programs"
ordering = [
"rank",
]
unique_together = ["date", "gymnast", "rank"]
gymnast = models.ForeignKey("people.Gymnast", on_delete=models.CASCADE) # TO DELETE
passe = models.ForeignKey(Passe, on_delete=models.CASCADE)
repetition = models.PositiveSmallIntegerField(default=1)
number_of_skill = models.PositiveSmallIntegerField(default=0)
difficulty = models.DecimalField(max_digits=4, decimal_places=1, default=0.0)
rank = models.PositiveSmallIntegerField(default=1) # TO DELETE
score = models.PositiveSmallIntegerField(blank=True, null=True) # TO DELETE
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return (
f"{self.gymnast} {self.date} - {self.rank} : {self.passe} {self.repetition}"
)
def save(self, *args, **kwargs):
"""Sauve les informations de la personne et initialise les champs nettoyés."""
super().save(*args, **kwargs)
self.difficulty = self.passe.difficulty * self.repetition
self.number_of_skill = self.passe.number_of_skill * self.repetition
super().save(*args, **kwargs)
# class TrainingPasseLink(models.Model):
# """Modèle M2M entre Training et TrainingPasse."""
# training = models.ForeignKey(
# Training,
# on_delete=models.CASCADE,
# default=None,
# related_name="program_passe_links",
# )
# program_passe = models.ForeignKey(
# TrainingPasse,
# on_delete=models.CASCADE,
# default=None,
# related_name="training_links",
# )
# rank = models.PositiveSmallIntegerField(default=1)
# number_of_skill = models.PositiveSmallIntegerField(default=0)
# difficulty = models.DecimalField(max_digits=4, decimal_places=1, default=0.0)
# score = models.PositiveSmallIntegerField(blank=True, null=True)
# class Training(Seasonisable, Markdownizable):
# """Classe représentant un entraînement."""
# gymnast = models.ForeignKey("people.Gymnast", on_delete=models.CASCADE)
# difficulty = models.DecimalField(max_digits=4, decimal_places=1, default=0.0)
# number_of_skill = models.PositiveSmallIntegerField(default=0)
# score = models.PositiveSmallIntegerField(default=1)

View File

@ -14,31 +14,31 @@
{{ hidden }}
{% endfor %}
<div class="form-group row {% if form.long_label.errors %}has-error has-feedback{% endif %}">
<label for="id_long_label" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Long label <span class="text-danger"><b>*</b></span></label>
<div class="col-8 col-sm-10 col-md-10 col-lg-10 col-xl-10">
<label for="id_long_label" class="col-4 col-sm-3 col-md-3 col-lg-3 col-xl-3 col-form-label">Long label <span class="text-danger"><b>*</b></span></label>
<div class="col-8 col-sm-9 col-md-9 col-lg-9 col-xl-9">
{{ form.long_label }}&nbsp;{% if form.long_label.errors %}
{% for error in form.long_label.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row {% if form.short_label.errors %}has-error has-feedback{% endif %}">
<label for="id_short_label" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Short label <span class="text-danger"><b>*</b></span></label>
<div class="col-8 col-sm-10 col-md-10 col-lg-10 col-xl-10">
{{ form.short_label }}&nbsp;{% if form.short_label.errors %}<span class="btn btn-sm btn-danger-outline">{% for error in form.short_label.errors %}{{ error }}{% endfor %}</span>{% endif %}
<label for="id_short_label" class="col-4 col-sm-3 col-md-3 col-lg-3 col-xl-3 col-form-label">Short label <span class="text-danger"><b>*</b></span></label>
<div class="col-8 col-sm-9 col-md-9 col-lg-9 col-xl-9">
{{ form.short_label }}&nbsp;{% if form.short_label.errors %}<span class="btn btn-sm">{% for error in form.short_label.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row {% if form.is_routine.errors %}has-error has-feedback{% endif %}">
<label for="id_is_routine" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Is routine ? <span class="text-danger"><b>*</b></span></label>
<div class="col-8 col-sm-10 col-md-10 col-lg-10 col-xl-10">
{{ form.is_routine }}&nbsp;{% if form.is_routine.errors %}<span class="btn btn-sm btn-danger-outline">{% for error in form.is_routine.errors %}{{ error }}{% endfor %}</span>{% endif %}
<label for="id_is_routine" class="col-4 col-sm-3 col-md-3 col-lg-3 col-xl-3 col-form-label">Is routine ? <span class="text-danger"><b>*</b></span></label>
<div class="col-8 col-sm-9 col-md-9 col-lg-9 col-xl-9">
{{ form.is_routine }}&nbsp;{% if form.is_routine.errors %}<span class="btn btn-sm">{% for error in form.is_routine.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row {% if form.is_competitive.errors %}has-error has-feedback{% endif %}">
<label for="id_is_competitive" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Is Competitive ? <span class="text-danger"><b>*</b></span></label>
<div class="col-8 col-sm-10 col-md-10 col-lg-10 col-xl-10">
{{ form.is_competitive }}&nbsp;{% if form.is_competitive.errors %}<span class="btn btn-sm btn-danger-outline">{% for error in form.is_competitive.errors %}{{ error }}{% endfor %}</span>{% endif %}
<label for="id_is_competitive" class="col-4 col-sm-3 col-md-3 col-lg-3 col-xl-3 col-form-label">Is Competitive ? <span class="text-danger"><b>*</b></span></label>
<div class="col-8 col-sm-9 col-md-9 col-lg-9 col-xl-9">
{{ form.is_competitive }}&nbsp;{% if form.is_competitive.errors %}<span class="btn btn-sm">{% for error in form.is_competitive.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>

View File

@ -35,8 +35,8 @@
</div>
<div class="row mt-2">
<div class="col-6 text-center">Routine : <a href="#">{% if routine.is_routine %}Yes{% else %}No{% endif %}</a></div>
<div class="col-6 text-center">Competition : <a href="#">{% if routine.is_competitive %}Yes{% else %}No{% endif %}</a></div>
<div class="col-6 text-center">Routine : <a href="#">{% if combination.is_routine %}Yes{% else %}No{% endif %}</a></div>
<div class="col-6 text-center">Competition : <a href="#">{% if combination.is_competitive %}Yes{% else %}No{% endif %}</a></div>
</div>
{% else %}

View File

@ -11,18 +11,18 @@
<div class="col-1 ml-auto">
<div class="text-right">
{% if request.user|has_group:"trainer" %}
<a href="{% url 'combination_create' %}">
<button type="submit" value="add" class="btn btn-icon btn-warning mb-0">
<i class="fas fa-plus"></i>
</button>
</a>
<h3 class="mb-0">
<a href="{% url 'combination_create' %}">
<i class="fas fa-plus text-warning"></i>
</a>
</h3>
{% endif %}
</div>
</div>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<div class="card-body pt-0 pb-0">
<div class="table-responsive pb-0">
{% if routine_list %}
<table class="table tablesorter table-striped" data-sort="table" id="routine_table">
<thead>

View File

@ -19,7 +19,7 @@
<label for="id_label" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Label</label>
<div class="col-8 col-sm-10 col-md-10 col-lg-10 col-xl-10">
{{ form.label }}
{% if form.label.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.label.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.label.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.label.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
@ -27,7 +27,7 @@
<label for="id_regexp" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">{{ form.regexp.label }}<span class="text-danger"><b>*</b></span></label>
<div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-3">
{{ form.regexp }}
{% if form.regexp.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.regexp.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.regexp.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.regexp.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>

View File

@ -17,9 +17,9 @@
<div class="card mb-0">
<div class="card-header">
<h3 class="mb-0">{{ skill.short_label }}</h3>
<h4 class="card-title"> {{ skill.notation }}</h4>
<h4 class="card-title mb-0"> {{ skill.notation }}</h4>
</div>
<div class="card-body pb-0 mb-0">
<div class="card-body pb-0 pt-0 mb-0">
<div class="row mr-1 ml-1 pb-0 mb-0">
<svg></svg>
</div>
@ -28,8 +28,9 @@
{% endblock %}
{% block footerscript %}
<script src="{% static "js/plugins/D3-dag/d3_7.6.1.min.js" %}"></script>
<script src="{% static "js/plugins/D3-dag/d3-dag_0.11.1.min.js" %}"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.9.0/d3.min.js" integrity="sha512-vc58qvvBdrDR4etbxMdlTt4GBQk1qjvyORR2nrsPsFPyrs+/u5c3+1Ct6upOgdZoIl7eq6k3a1UPDSNAQi/32A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-dag@0.11.1/bundle/d3-dag.iife.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
function compute_font_size(string)
{

View File

@ -5,8 +5,8 @@
<div class="card-header">
<h4 class=""> Skills Listing</h4>
</div>
<div class="card-body">
<div class="table-responsive">
<div class="card-body pt-0 pb-0">
<div class="table-responsive pb-0">
{% if skill_list %}
<table class="table tablesorter table-striped" data-sort="table" id="skill_table">
<thead class="text-primary">
@ -16,9 +16,9 @@
<th class="text-center">Notation</th>
<th class="text-center"><i class="far fa-venus"></i></th>
<th class="text-center"><i class="far fa-mars"></i></th>
<th class="header text-center" style="width: 7%">Diff.</th>
<th class="header text-center" style="width: 7%">Level</th>
<th class="header text-center" style="width: 7%">Rank</th>
<th class="text-center" style="width: 7%">Diff.</th>
<th class="text-center" style="width: 7%">Level</th>
<th class="text-center" style="width: 7%">Rank</th>
</tr>
</thead>
<tbody>
@ -75,7 +75,7 @@
})
$('#skill_table').DataTable({
scrollY: '50vh',
scrollY: '55vh',
scrollCollapse: true,
paging: false,
searching: false,

View File

@ -5,7 +5,7 @@ from jarvis.objective.models import (
TouchPosition,
Routine,
RoutineSkill,
Passe,
# Passe,
)
from jarvis.core.global_vars import ROUTINE_TYPE_CHOICE
@ -106,154 +106,154 @@ class ToolsModels(TestCase):
)
class PasseTestCase(TestCase):
def setUp(self):
"""
Structure finale :
1 -> 2
1 -> 6
3 -> 4 -> 5 -> 6 -> 7
1 -> 2 -> 9
3 -> 4 -> 5 -> 6 -> 7 -> 9
"""
# 1 et 3 Eductative sans pre-requis
educ_1 = Educative.objects.create(
long_label="1/2 vrille", difficulty=0.1, level=1, rank=1
)
educ_3 = Educative.objects.create(
long_label="4 pattes", difficulty=0.1, level=1, rank=1
)
# class PasseTestCase(TestCase):
# def setUp(self):
# """
# Structure finale :
# 1 -> 2
# 1 -> 6
# 3 -> 4 -> 5 -> 6 -> 7
# 1 -> 2 -> 9
# 3 -> 4 -> 5 -> 6 -> 7 -> 9
# """
# # 1 et 3 Eductative sans pre-requis
# educ_1 = Educative.objects.create(
# long_label="1/2 vrille", difficulty=0.1, level=1, rank=1
# )
# educ_3 = Educative.objects.create(
# long_label="4 pattes", difficulty=0.1, level=1, rank=1
# )
def test_is_valid_dot(self):
arg = ""
self.assertEqual(Passe.is_valid_dot(arg), True)
arg = "Q1R1"
self.assertEqual(Passe.is_valid_dot(arg), True)
arg = ".Q1R1"
self.assertEqual(Passe.is_valid_dot(arg), True)
arg = "Q1R1."
self.assertEqual(Passe.is_valid_dot(arg), True)
arg = "Q1.R1"
self.assertEqual(Passe.is_valid_dot(arg), False)
arg = ".Q1.R1."
self.assertEqual(Passe.is_valid_dot(arg), False)
# def test_is_valid_dot(self):
# arg = ""
# self.assertEqual(Passe.is_valid_dot(arg), True)
# arg = "Q1R1"
# self.assertEqual(Passe.is_valid_dot(arg), True)
# arg = ".Q1R1"
# self.assertEqual(Passe.is_valid_dot(arg), True)
# arg = "Q1R1."
# self.assertEqual(Passe.is_valid_dot(arg), True)
# arg = "Q1.R1"
# self.assertEqual(Passe.is_valid_dot(arg), False)
# arg = ".Q1.R1."
# self.assertEqual(Passe.is_valid_dot(arg), False)
def test_is_valid_subset(self):
subset = ""
self.assertEqual(Passe.is_valid_subset(subset), False)
subset = "[2-8]"
self.assertEqual(Passe.is_valid_subset(subset), True)
subset = "[2--8]"
self.assertEqual(Passe.is_valid_subset(subset), False)
subset = "[-5]"
self.assertEqual(Passe.is_valid_subset(subset), True)
subset = "[3-]"
self.assertEqual(Passe.is_valid_subset(subset), True)
subset = "[8-2]"
self.assertEqual(Passe.is_valid_subset(subset), False)
subset = "[-]"
self.assertEqual(Passe.is_valid_subset(subset), False)
subset = "[1-]"
self.assertEqual(Passe.is_valid_subset(subset), False)
subset = "[-1]"
self.assertEqual(Passe.is_valid_subset(subset), False)
subset = "[4]"
self.assertEqual(Passe.is_valid_subset(subset), False)
subset = "[6-6]"
self.assertEqual(Passe.is_valid_subset(subset), False)
subset = "4"
self.assertEqual(Passe.is_valid_subset(subset), False)
subset = "[6-6"
self.assertEqual(Passe.is_valid_subset(subset), False)
subset = "[66]"
self.assertEqual(Passe.is_valid_subset(subset), False)
subset = "4-8"
self.assertEqual(Passe.is_valid_subset(subset), False)
subset = "6-]"
self.assertEqual(Passe.is_valid_subset(subset), False)
subset = "[4-"
self.assertEqual(Passe.is_valid_subset(subset), False)
subset = "[6"
self.assertEqual(Passe.is_valid_subset(subset), False)
subset = "Q1R1 [4-8]"
self.assertEqual(Passe.is_valid_subset(subset), False)
subset = "Q1R1 [-8]"
self.assertEqual(Passe.is_valid_subset(subset), False)
# def test_is_valid_subset(self):
# subset = ""
# self.assertEqual(Passe.is_valid_subset(subset), False)
# subset = "[2-8]"
# self.assertEqual(Passe.is_valid_subset(subset), True)
# subset = "[2--8]"
# self.assertEqual(Passe.is_valid_subset(subset), False)
# subset = "[-5]"
# self.assertEqual(Passe.is_valid_subset(subset), True)
# subset = "[3-]"
# self.assertEqual(Passe.is_valid_subset(subset), True)
# subset = "[8-2]"
# self.assertEqual(Passe.is_valid_subset(subset), False)
# subset = "[-]"
# self.assertEqual(Passe.is_valid_subset(subset), False)
# subset = "[1-]"
# self.assertEqual(Passe.is_valid_subset(subset), False)
# subset = "[-1]"
# self.assertEqual(Passe.is_valid_subset(subset), False)
# subset = "[4]"
# self.assertEqual(Passe.is_valid_subset(subset), False)
# subset = "[6-6]"
# self.assertEqual(Passe.is_valid_subset(subset), False)
# subset = "4"
# self.assertEqual(Passe.is_valid_subset(subset), False)
# subset = "[6-6"
# self.assertEqual(Passe.is_valid_subset(subset), False)
# subset = "[66]"
# self.assertEqual(Passe.is_valid_subset(subset), False)
# subset = "4-8"
# self.assertEqual(Passe.is_valid_subset(subset), False)
# subset = "6-]"
# self.assertEqual(Passe.is_valid_subset(subset), False)
# subset = "[4-"
# self.assertEqual(Passe.is_valid_subset(subset), False)
# subset = "[6"
# self.assertEqual(Passe.is_valid_subset(subset), False)
# subset = "Q1R1 [4-8]"
# self.assertEqual(Passe.is_valid_subset(subset), False)
# subset = "Q1R1 [-8]"
# self.assertEqual(Passe.is_valid_subset(subset), False)
def test_is_valid_routine_type(self):
for item in ROUTINE_TYPE_CHOICE:
self.assertEqual(Passe.is_valid_routine_type(item[1]), True)
# def test_is_valid_routine_type(self):
# for item in ROUTINE_TYPE_CHOICE:
# self.assertEqual(Passe.is_valid_routine_type(item[1]), True)
routine_type = ""
self.assertEqual(Passe.is_valid_routine_type(routine_type), False)
routine_type = ".Q1R1"
self.assertEqual(Passe.is_valid_routine_type(routine_type), False)
routine_type = "SFS."
self.assertEqual(Passe.is_valid_routine_type(routine_type), False)
routine_type = "Q1R1 [4-8]"
self.assertEqual(Passe.is_valid_routine_type(routine_type), False)
routine_type = "SFS [-8]"
self.assertEqual(Passe.is_valid_routine_type(routine_type), False)
# routine_type = ""
# self.assertEqual(Passe.is_valid_routine_type(routine_type), False)
# routine_type = ".Q1R1"
# self.assertEqual(Passe.is_valid_routine_type(routine_type), False)
# routine_type = "SFS."
# self.assertEqual(Passe.is_valid_routine_type(routine_type), False)
# routine_type = "Q1R1 [4-8]"
# self.assertEqual(Passe.is_valid_routine_type(routine_type), False)
# routine_type = "SFS [-8]"
# self.assertEqual(Passe.is_valid_routine_type(routine_type), False)
def test_is_valid_regexp_one_arg(self):
arg = ""
self.assertEqual(Passe.is_valid_regexp_one_arg(arg), False)
arg = "WC"
self.assertEqual(Passe.is_valid_regexp_one_arg(arg), True)
arg = "1|"
self.assertEqual(Passe.is_valid_regexp_one_arg(arg), True)
arg = ".Q1R1"
self.assertEqual(Passe.is_valid_regexp_one_arg(arg), True)
arg = "Q1R2."
self.assertEqual(Passe.is_valid_regexp_one_arg(arg), True)
arg = ".Q1R1 [4-8"
self.assertEqual(Passe.is_valid_regexp_one_arg(arg), False)
arg = "Q1R2. [4-8"
self.assertEqual(Passe.is_valid_regexp_one_arg(arg), False)
arg = "Q1R1 [4-8]"
self.assertEqual(Passe.is_valid_regexp_one_arg(arg), False)
arg = "Q1R1 [8-4]"
self.assertEqual(Passe.is_valid_regexp_one_arg(arg), False)
# def test_is_valid_regexp_one_arg(self):
# arg = ""
# self.assertEqual(Passe.is_valid_regexp_one_arg(arg), False)
# arg = "WC"
# self.assertEqual(Passe.is_valid_regexp_one_arg(arg), True)
# arg = "1|"
# self.assertEqual(Passe.is_valid_regexp_one_arg(arg), True)
# arg = ".Q1R1"
# self.assertEqual(Passe.is_valid_regexp_one_arg(arg), True)
# arg = "Q1R2."
# self.assertEqual(Passe.is_valid_regexp_one_arg(arg), True)
# arg = ".Q1R1 [4-8"
# self.assertEqual(Passe.is_valid_regexp_one_arg(arg), False)
# arg = "Q1R2. [4-8"
# self.assertEqual(Passe.is_valid_regexp_one_arg(arg), False)
# arg = "Q1R1 [4-8]"
# self.assertEqual(Passe.is_valid_regexp_one_arg(arg), False)
# arg = "Q1R1 [8-4]"
# self.assertEqual(Passe.is_valid_regexp_one_arg(arg), False)
def test_is_valid_regexp_two_args(self):
arg1 = ""
arg2 = ""
self.assertEqual(Passe.is_valid_regexp_two_args(arg1, arg2), False)
arg1 = "Q1R1"
self.assertEqual(Passe.is_valid_regexp_two_args(arg1, arg2), False)
arg2 = "[4-8]"
self.assertEqual(Passe.is_valid_regexp_two_args(arg1, arg2), True)
arg2 = "[8-8]"
self.assertEqual(Passe.is_valid_regexp_two_args(arg1, arg2), False)
arg2 = "[8-4]"
self.assertEqual(Passe.is_valid_regexp_two_args(arg1, arg2), False)
arg2 = "[-8]"
self.assertEqual(Passe.is_valid_regexp_two_args(arg1, arg2), True)
arg2 = "[4-]"
self.assertEqual(Passe.is_valid_regexp_two_args(arg1, arg2), True)
arg1 = "Q1R1."
self.assertEqual(Passe.is_valid_regexp_two_args(arg1, arg2), True)
# def test_is_valid_regexp_two_args(self):
# arg1 = ""
# arg2 = ""
# self.assertEqual(Passe.is_valid_regexp_two_args(arg1, arg2), False)
# arg1 = "Q1R1"
# self.assertEqual(Passe.is_valid_regexp_two_args(arg1, arg2), False)
# arg2 = "[4-8]"
# self.assertEqual(Passe.is_valid_regexp_two_args(arg1, arg2), True)
# arg2 = "[8-8]"
# self.assertEqual(Passe.is_valid_regexp_two_args(arg1, arg2), False)
# arg2 = "[8-4]"
# self.assertEqual(Passe.is_valid_regexp_two_args(arg1, arg2), False)
# arg2 = "[-8]"
# self.assertEqual(Passe.is_valid_regexp_two_args(arg1, arg2), True)
# arg2 = "[4-]"
# self.assertEqual(Passe.is_valid_regexp_two_args(arg1, arg2), True)
# arg1 = "Q1R1."
# self.assertEqual(Passe.is_valid_regexp_two_args(arg1, arg2), True)
def test_is_valid_regexp(self):
regexp = ""
self.assertEqual(Passe.is_valid_regexp(regexp), False)
regexp = "Q1R1 [4-8]"
self.assertEqual(Passe.is_valid_regexp(regexp), True)
regexp = "Q1R1 [8-8]"
self.assertEqual(Passe.is_valid_regexp(regexp), False)
regexp = "Q1R1 [8-4]"
self.assertEqual(Passe.is_valid_regexp(regexp), False)
regexp = "Q1R1 [-8]"
self.assertEqual(Passe.is_valid_regexp(regexp), True)
regexp = "Q1R1 [4-]"
self.assertEqual(Passe.is_valid_regexp(regexp), True)
regexp = "Q1R1. [4-8]"
self.assertEqual(Passe.is_valid_regexp(regexp), True)
regexp = "Q1R1. [4-]"
self.assertEqual(Passe.is_valid_regexp(regexp), True)
regexp = ".Q1R1 [-8]"
self.assertEqual(Passe.is_valid_regexp(regexp), True)
regexp = "Q1R1. [8-8]"
self.assertEqual(Passe.is_valid_regexp(regexp), False)
regexp = ".Q1R1 [8-4]"
self.assertEqual(Passe.is_valid_regexp(regexp), False)
# def test_is_valid_regexp(self):
# regexp = ""
# self.assertEqual(Passe.is_valid_regexp(regexp), False)
# regexp = "Q1R1 [4-8]"
# self.assertEqual(Passe.is_valid_regexp(regexp), True)
# regexp = "Q1R1 [8-8]"
# self.assertEqual(Passe.is_valid_regexp(regexp), False)
# regexp = "Q1R1 [8-4]"
# self.assertEqual(Passe.is_valid_regexp(regexp), False)
# regexp = "Q1R1 [-8]"
# self.assertEqual(Passe.is_valid_regexp(regexp), True)
# regexp = "Q1R1 [4-]"
# self.assertEqual(Passe.is_valid_regexp(regexp), True)
# regexp = "Q1R1. [4-8]"
# self.assertEqual(Passe.is_valid_regexp(regexp), True)
# regexp = "Q1R1. [4-]"
# self.assertEqual(Passe.is_valid_regexp(regexp), True)
# regexp = ".Q1R1 [-8]"
# self.assertEqual(Passe.is_valid_regexp(regexp), True)
# regexp = "Q1R1. [8-8]"
# self.assertEqual(Passe.is_valid_regexp(regexp), False)
# regexp = ".Q1R1 [8-4]"
# self.assertEqual(Passe.is_valid_regexp(regexp), False)

View File

@ -133,7 +133,6 @@ class ToolsTestCase(TestCase):
self.assertEqual(nb_skill_lte_type(4, "level"), 9)
def test_compute_completude(self):
self.assertEqual(compute_completude(10, 1, 4), ("10%", 0))
self.assertEqual(compute_completude(10, 1, 4), ("10%", 0))
self.assertEqual(compute_completude(10, 5, 4), ("50%", 2))
self.assertEqual(compute_completude(10, 10, 4), ("100%", 4))
self.assertEqual(compute_completude(10, 1, 4), ('10%', 0, 10))
self.assertEqual(compute_completude(10, 5, 4), ('50%', 2, 50))
self.assertEqual(compute_completude(10, 10, 4), ('100%', 4, 100))

View File

@ -69,8 +69,9 @@ def compute_completude(total_skill, gymnast_nb_known_skills, max_level_skill):
max_skill (int): nombre maximum de skill.
Returns:
string: pourcentage de skill connus.
string: pourcentage de skill connus sous forme de string.
int: niveau estimé du gymnaste.
float: pourcentage de skill connus sous forme de nombre
Example:
>>> from jarvis.objective.tools import compute_completude
@ -80,11 +81,12 @@ def compute_completude(total_skill, gymnast_nb_known_skills, max_level_skill):
if total_skill:
percentage = gymnast_nb_known_skills / total_skill
completude = f"{int(percentage * 100)}%"
evaluated_level = int(max_level_skill * percentage)
estimated_level = int(max_level_skill * percentage)
else:
percentage = 0
completude = None
evaluated_level = None
return completude, evaluated_level
estimated_level = None
return completude, estimated_level, int(percentage * 100)
def compute_statistics_by_type(

View File

@ -37,7 +37,7 @@ urlpatterns = [
# COMBINATION
#
path(
r"combination/lookup/<str:search_type>",
r"combination/lookup/",
views.combination_lookup,
name="combination_lookup",
),
@ -89,36 +89,4 @@ urlpatterns = [
name="competition_routine_listing",
),
path(r"combination/", views.combination_listing, name="combination_listing"),
#
# PASSES
#
path(
r"passe/<int:passe_id>/gymnast/<int:gymnast_id>/date/<str:date>/",
views.passe_details,
name="passe_details",
),
path(r"passe/", views.passe_listing, name="passe_listing"),
path(
r"passe/add/",
views.passe_create_or_update,
name="passe_create",
),
path(
r"passe/edit/<int:passe_id>/",
views.passe_create_or_update,
name="passe_update",
),
#
# TRAININGPROGRAM
#
path(
r"trainingprogram/detail/date/<str:date>/gymnast/<int:gymnast_id>/",
views.trainingprogram_details,
name="trainingprogram_details",
),
path(
r"trainingprogram/switch_trainingprogram_line/",
views.switch_trainingprogram_line,
name="switch_trainingprogram_line",
),
]

View File

@ -5,25 +5,18 @@ from django.shortcuts import render, get_object_or_404
from django.views.decorators.http import require_http_methods
from django.urls import reverse
import pendulum
from jarvis.core.global_vars import ROUTINE_TYPE_CHOICE
from jarvis.people.models import Gymnast
from jarvis.followup.models import GymnastHasRoutine
from .forms import (
SkillForm,
PasseForm,
CombinationForm,
CombinationSkillForm,
)
from .models import (
Skill,
Passe,
Routine,
Educative,
RoutineSkill,
TrainingProgram,
PrerequisiteClosure,
)
@ -510,191 +503,3 @@ def unlink_skill_from_combination(request):
return HttpResponse(409)
return HttpResponse(200)
@login_required
@require_http_methods(["GET"])
def passe_listing(request):
"""Liste des passages."""
passe_listing = Passe.objects.all()
context = {"passe_listing": passe_listing}
return render(request, "passes/list.html", context)
@login_required
@require_http_methods(["GET"])
def passe_details(request, passe_id, gymnast_id, date):
"""Détails d'un passage."""
is_skill = False
passe = get_object_or_404(Passe, pk=passe_id)
educative_list = passe.educatives.all()
# TODO: décryptage de la regexp
regexp = passe.regexp
routine = None
skill_link_list = None
if regexp is not None:
operation_list = regexp.split(" ")
routine_type = None
for item in ROUTINE_TYPE_CHOICE:
if item[1] == operation_list[0]:
routine_type = item[0]
break
if routine_type is not None:
# Récupération de la série
ghr = GymnastHasRoutine.objects.filter(
gymnast=gymnast_id,
date_begin__lte=date,
# date_end__gte=date,
routine_type=routine_type,
)
print(ghr.query)
if ghr.count() > 1:
print("Plus d'une série trouvée...")
print(ghr)
routine = ghr.first().routine
skill_link_list = routine.skill_links.all()
if len(operation_list) == 2:
content = operation_list[1].replace("[", "").replace("]", "")
ranks = content.split("-")
if ranks[0] != "":
skill_link_list = skill_link_list.filter(rank__gte=ranks[0])
if ranks[1] != "":
skill_link_list = skill_link_list.filter(rank__lte=ranks[1])
number_of_educative = skill_link_list.count()
print(number_of_educative)
else:
number_of_educative = educative_list.count()
context = {
"passe": passe,
"is_skill": is_skill,
"educative_list": educative_list,
"routine": routine,
"skill_link_list": skill_link_list,
"difficulty": passe.difficulty,
"number_of_skill": passe.number_of_skill,
"number_of_educative": number_of_educative,
}
return render(request, "passes/details.html", context)
@login_required
@require_http_methods(["GET", "POST"])
def passe_create_or_update(request, passe_id=None):
"""Création d'un passage.
Args:
passe_id (int) identifiant d'un object de classe <Passe>.
"""
if passe_id:
passe = get_object_or_404(Passe, pk=passe_id)
else:
passe = None
if request.method == "POST":
form = PasseForm(request.POST, instance=passe)
if form.is_valid():
passe = form.save()
return HttpResponseRedirect(reverse("passe_details", args=(passe.pk,)))
return render(request, "passes/create.html", {"form": form})
form = PasseForm(instance=passe)
context = {"form": form, "passe_id": passe_id}
return render(request, "passes/create.html", context)
@login_required
@require_http_methods(["GET"])
def trainingprogram_details(request, date=None, gymnast_id=None):
"""Détails d'un entraînement."""
gymnast = None
trainingprogram_id = None
if trainingprogram_id is not None:
trainingprogram = get_object_or_404(TrainingProgram, pk=trainingprogram_id)
trainingprogram_list = None
else:
trainingprogram = None
trainingprogram_list = TrainingProgram.objects.all()
parsed_date = pendulum.parse(date).date()
if date is not None:
trainingprogram_list = trainingprogram_list.filter(date=parsed_date)
if gymnast_id is not None:
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
trainingprogram_list = trainingprogram_list.filter(gymnast=gymnast_id)
difficulty = 0
number_of_skill = 0
for trainingprogram in trainingprogram_list:
difficulty += trainingprogram.difficulty
number_of_skill += trainingprogram.number_of_skill
context = {
"gymnast": gymnast,
"date": parsed_date,
"difficulty": difficulty,
"number_of_skill": number_of_skill,
"trainingprogram": trainingprogram,
"trainingprogram_list": trainingprogram_list,
}
return render(request, "trainingprograms/details.html", context)
@require_http_methods(["POST"])
def switch_trainingprogram_line(request):
"""
Recoit dans request deux identifiants de trainingprogram qu'il faut échanger () :
- tp_id (int) identifiant d'une instance de TraiingProgram
- direction (str) la direction du changement (0: haut, 1: bas)
J'utilise `32767` comme valeur intermédiaire pour le `rank` car c'est la limite supérieure d'un
PositiveSmallIntegerField.
"""
try:
target_trainingprogram_id = request.POST.get("tpid", None)
direction = int(request.POST.get("direction", 0))
target_trainingprogram = get_object_or_404(
TrainingProgram, pk=target_trainingprogram_id
)
if direction == 0:
source_trainingprogram = (
TrainingProgram.objects.filter(rank__lt=target_trainingprogram.rank)
.order_by("-id")
.first()
)
else:
source_trainingprogram = (
TrainingProgram.objects.filter(rank__gt=target_trainingprogram.rank)
.order_by("id")
.first()
)
saved_source_rank = source_trainingprogram.rank
saved_target_rank = target_trainingprogram.rank
source_trainingprogram.rank = 32767
source_trainingprogram.save()
target_trainingprogram.rank = saved_source_rank
target_trainingprogram.save()
source_trainingprogram.rank = saved_target_rank
source_trainingprogram.save()
return HttpResponse(200)
except Exception:
return HttpResponse(409)

View File

@ -0,0 +1,21 @@
# Generated by Django 4.2 on 2024-03-25 11:58
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("people", "0011_gymnast_trainers"),
]
operations = [
migrations.AlterModelOptions(
name="gymnast",
options={
"ordering": ["first_name", "last_name"],
"verbose_name": "Gymnast",
"verbose_name_plural": "Gymnasts",
},
),
]

View File

@ -221,7 +221,7 @@ class Gymnast(Markdownizable):
"""
Calcule toutes les statistiques par rapport au niveau/rang suivant le paramètre transmis.
1. On va chercher le niveau/rang maximum de skill que le gymnast sait faire
1. On va chercher le type (niveau ou rang) maximum de skill que le gymnast sait faire
2. 0n va chercher le nombre de skill par niveau/rang que le gymnast sait faire
nb_known_skill_by_type = [
{
@ -259,6 +259,7 @@ class Gymnast(Markdownizable):
context = {}
skill_max = self.skill_max_for_type(desired_type)
gymnast_nb_known_skills = self.known_skills.distinct("skill").count()
context["gymnast_nb_known_skills"] = gymnast_nb_known_skills
if skill_max > 0:
cpt_known_skill_by_type = self.nb_known_skill_by_type(
@ -275,10 +276,16 @@ class Gymnast(Markdownizable):
tmp = Skill.objects.all()
context["total_skill"] = tmp.count()
context["unknown_skill"] = tmp
context["percentages"] = 0
context["completude"], context["evaluated_level"] = compute_completude(
context["completude"], context["estimated_level"], context["percentage_known_skill"] = compute_completude(
context["total_skill"], gymnast_nb_known_skills, skill_max
)
# print(context["percentage_known_skill"])
# print(context["gymnast_nb_known_skills"])
# print(context["completude"])
# print(context["estimated_level"])
context["max_" + desired_type + "_skill"] = skill_max
return context

View File

@ -16,11 +16,11 @@
<div class="row">
<div class="col-12 col-sm-6 col-md-6 col-lg-6 col-xl-6 pr-0">
{{ form.first_name }}
{% if form.first_name.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.first_name.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.first_name.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.first_name.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
<div class="col-12 col-sm-6 col-md-6 col-lg-6 col-xl-6">
{{ form.last_name }}
{% if form.last_name.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.last_name.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.last_name.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.last_name.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
</div>
@ -29,28 +29,28 @@
<label for="id_birthdate" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-3 col-form-label">Birthdate <span class="text-danger"><b>*</b></span></label>
<div class="col-8 col-sm-3 col-md-3 col-lg-3 col-xl-3">
{{ form.birthdate }}
{% if form.birthdate.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.birthdate.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.birthdate.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.birthdate.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row {% if form.gender.errors %}has-error has-feedback{% endif %}">
<label for="id_gender" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-3 col-form-label">Gender <span class="text-danger"><b>*</b></span></label>
<div class="col-8 col-sm-3 col-md-3 col-lg-3 col-xl-3">
{{ form.gender }}
{% if form.gender.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.gender.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.gender.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.gender.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row {% if form.email.errors %}has-error has-feedback{% endif %}">
<label for="id_email" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-3 col-form-label">Email</label>
<div class="col-12 col-sm-10 col-md-6 col-lg-6 col-xl-6">
{{ form.email }}
{% if form.email.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.email.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.email.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.email.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row {% if form.orientation.errors %}has-error has-feedback{% endif %}">
<label for="id_orientation" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-3 col-form-label">Orientation <span class="text-danger"><b>*</b></span></label>
<div class="col-8 col-sm-3 col-md-3 col-lg-2 col-xl-2">
{{ form.orientation }}
{% if form.orientation.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.orientation.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.orientation.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.orientation.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row">
@ -70,7 +70,7 @@
<label for="id_email_trainer" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-3 col-form-label">Email trainer</label>
<div class="col-12 col-sm-10 col-md-6 col-lg-6 col-xl-6">
{{ form.email_trainer }}
{% if form.email_trainer.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.email_trainer.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.email_trainer.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.email_trainer.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
@ -84,7 +84,7 @@
<label for="id_is_active" class="col-4 col-sm-2 col-md-3 col-lg-3 col-xl-3 col-form-label">Is active</label>
<div class="col-8 col-sm-2 col-md-2 col-lg-2 col-xl-2">
{{ form.is_active }}
{% if form.is_active.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.is_active.errors %}{{ error }}{% endfor %}</span>{% endif %}
{% if form.is_active.errors %}&nbsp;<span class="btn btn-sm">{% for error in form.is_active.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
{% else %}

View File

@ -3,13 +3,12 @@
{% load skill_doughnut %}
{% load level_chart_bar %}
{% load has_group %}
{% load is_user_equal_to_gymnast %}
{% block page_title %}{{ gymnast.first_name }} {{ gymnast.last_name }}{% endblock %}
{% block content %}
<div class="row">
<div class="col-12 col-sm-12 col-md-4 col-lg-4">
<div class="col-12 col-md-4 pl-0 pr-0">
<div class="card card-user mb-4">
<div class="card-body">
<div class="author">
@ -25,7 +24,7 @@
</a>
<p class="description">
{{ last_season_information.club.name }}<br />
<b>{{ last_season_information.get_category_display }}</b>
<b>{{ last_season_information.category.short_label }}</b>
</p>
</div>
<div class="card-description">
@ -47,16 +46,12 @@
<li>
<b>Routine</b> : {% if best_routine %}<b>{{ best_routine.0.tof }}</b> ({{ best_routine.0.date | date:"d-m-Y" }}){% else %} <span class="text-muted">(no information)</span>{% endif %}
</li>
{% if user_is_trainer %}
<a href="{% url 'add_season_information_for_gymnast' gymnast.id %}">Add season details</a> -
<a href="{% url 'season_information_for_gymnast' gymnast.id %}">Seasons details</a>
{% endif %}
</div>
</div>
</div>
</div>
<div class="col-12 col-sm-12 col-md-4 col-lg-4">
<div class="col-12 col-md-4 mb-4">
{% if gymnast_nb_known_skills %}
{% generate_skill_doughnut gymnast.id %}
{% else %}
@ -64,7 +59,7 @@
{% endif %}
</div>
<div class="col-12 col-sm-12 col-md-4 card mb-4">
<div class="col-12 col-md-4 card">
{% if gymnast_nb_known_skills %}
{% generate_level_chart_bar gymnast.id %}
{% else %}
@ -75,18 +70,12 @@
</div>
<div class="row">
<div class="col-12 col-sm-1 col-md-1 col-lg-1 col-xl-1">
<div class="col-12 col-sm-1 mb-4">
<ul class="nav nav-pills nav-pills-primary nav-pills-icons justify-content-center">
<li class="nav-item">
<a class="nav-link get-info{% if tab is None or tab == 'level' %} active{% endif %}" data-toggle="tab" href="#skill" data-ref="#skill" data-url="skill/" id="display_skill">
<i class="tim-icons icon-sound-wave"></i> <!-- Level -->
</a>
</li>
<li class="nav-item">
<a class="nav-link get-info{% if tab == 'document' %} active{% endif %}" data-toggle="tab" href="#document" data-ref="#document" data-url="document/" id="display_documents">
<i class="fal fa-file-pdf"></i> <!-- Documents -->
<i class="fal fa-hexagon"></i> <!-- Level -->
</a>
</li>
@ -98,7 +87,7 @@
<li class="nav-item">
<a class="nav-link get-info{% if tab == 'scores' %} active{% endif %}" data-toggle="tab" href="#scores" data-ref="#scores" data-url="scores_chrono/" id="display_scores_chrono">
<i class="fal fa-crosshairs"></i> <!-- Scores -->
<i class="fal fa-tasks-alt"></i> <!-- Scores -->
</a>
</li>
@ -109,20 +98,33 @@
</li>
<li class="nav-item">
<a class="nav-link get-info{% if tab == 'event' %} active{% endif %} mr-2 mb-1" data-toggle="tab" href="#event" data-ref="#event" data-url="event/" id="display_event">
<a class="nav-link get-info{% if tab == 'event' %} active{% endif %}" data-toggle="tab" href="#event" data-ref="#event" data-url="event/" id="display_event">
<i class="fal fa-calendar-day"></i> <!-- Events -->
</a>
</li>
<li class="nav-item">
<a class="nav-link get-info{% if tab == 'season_informations' %} active{% endif %}" data-toggle="tab" href="#season_informations" data-ref="#season_informations" data-url="season_informations/" id="display_season_informations">
<i class="fal fa-map-signs"></i> <!-- Season Informations -->
</a>
</li>
<li class="nav-item">
<a class="nav-link get-info{% if tab == 'document' %} active{% endif %} mr-2 mb-1" data-toggle="tab" href="#document" data-ref="#document" data-url="document/" id="display_documents">
<i class="fal fa-file-pdf"></i> <!-- Documents -->
</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-11 col-md-11 col-lg-11 pr-0">
<div class="tab-content">
<div class="tab-pane{% if tab is None or tab == 'skill' %} active{% endif %}" id="skill"></div>
<div class="tab-pane{% if tab == 'document' %} active{% endif %}" id="document"></div>
<div class="tab-pane{% if tab == 'routine' %} active{% endif %}" id="routine"></div>
<div class="tab-pane{% if tab == 'scores' %} active{% endif %}" id="scores"></div>
<div class="tab-pane{% if tab == 'physiological' %} active{% endif %}" id="physiological"></div>
<div class="tab-pane{% if tab == 'event' %} active{% endif %}" id="event"></div>
<div class="tab-pane{% if tab == 'season_informations' %} active{% endif %}" id="season_informations"></div>
<div class="tab-pane{% if tab == 'document' %} active{% endif %}" id="document"></div>
</div>
</div>
</div>
@ -139,9 +141,6 @@
{% if tab is None or tab == 'skill' %}
tab_url = default_url + 'skill/';
tab_div = '#skill';
{% elif tab == 'document' %}
tab_url = default_url + 'document/';
tab_div = '#document';
{% elif tab == 'routine' %}
tab_url = default_url + 'routine/';
tab_div = '#routine';
@ -154,6 +153,12 @@
{% elif tab == 'event' %}
tab_url = default_url + 'event/';
tab_div = '#event';
{% elif tab == 'season_informations' %}
tab_url = default_url + 'season_informations/';
tab_div = '#season_informations';
{% elif tab == 'document' %}
tab_url = default_url + 'document/';
tab_div = '#document';
{% endif %}
$.ajax({

View File

@ -1,5 +1,5 @@
<h4 class="d-flex align-items-end flex-column">
Estimated level : {% if gymnast_nb_known_skills %}{{ evaluated_level }}{% else %}0{% endif %}
Estimated level : {% if gymnast_nb_known_skills %}{{ estimated_level }}{% else %}0{% endif %}
</h4>
<div class="progress-container progress-primary">
<div class="progress" style="height: 10px;">

View File

@ -20,7 +20,7 @@
{{ form.gymnast }}
{{ form.gymnast_related }}
{% if form.gymnast.errors %}
<span class="btn btn-sm btn-danger-outline">
<span class="btn btn-sm">
{% for error in form.gymnast.errors %}{{ error }}{% endfor %}
</span>
{% endif %}

View File

@ -0,0 +1,66 @@
{% extends "base.html" %}
{% load static %}
{% load has_group %}
{% load is_user_equal_to_gymnast %}
{% block content %}
<div class="row justify-content-center">
<div class="col-12 col-sm-12 col-md-8 col-lg-8 col-xl-6">
<div class="card">
<div class="card-header">
<h4 class=" ">Link trainer to <a href="{% url 'gymnast_details_tab' gymnast.id 'season_informations' %}">{% if request.user|is_user_equal_to_gymnast:gymnastid %}you{% else %}{{ gymnast }}{% endif %}</a></h4>
</div>
<div class="card-body">
{% for trainer in trainers_list %}
{% if trainer != gymnast.user %}
<div class="form-group row mb-0">
<div class="col-md-8 ml-3">
{{ trainer.first_name }} {{ trainer.last_name }} {% if trainer.is_superuser %}<span class="text-muted">(Admin)</span>{% endif %}
</div>
<div class="col-md-3">
<input type="checkbox" name="checkbox" class="trainer_check" data-trainer="{{ trainer.id }}" {% if trainer.id in already_linked %}checked{% endif %} {% if trainer.is_superuser %}disabled="disabled"{% endif %}/>
</div>
<hr />
</div>
{% endif %}
{% endfor %}
</form>
</div>
</div>
</div>
</div>
{% endblock %}
{% block footerscript %}
<script type="text/javascript">
$(document).ready(function() {
$('.trainer_check').change(function() {
if(this.checked) {
$.ajax({
url: "{% url 'link_trainer_to_gymnast' gymnast.id %}",
method: "POST",
data: {
trainer_id: $(this).data("trainer"),
csrfmiddlewaretoken: '{{ csrf_token }}'
},
success: function(data) {
}
});
} else {
$.ajax({
url: "{% url 'unlink_trainer_to_gymnast' gymnast.id %}",
method: "POST",
data: {
trainer_id: $(this).data("trainer"),
csrfmiddlewaretoken: '{{ csrf_token }}'
},
success: function(data) {
}
});
}
});
});
</script>
{% endblock %}

View File

@ -21,7 +21,7 @@
</div>
</div>
</div>
<div class="card-body pt-0">
<div class="card-body pt-0 pb-0">
<div class="table-responsive pb-0">
{% if season_information_list %}
<table class="table tablesorter table-striped" data-sort="table" id="gymnast_table">
@ -33,7 +33,7 @@
<th class="header text-left" style="width: 20%">Lastname</th>
<th class="header text-left" style="width: 20%">Firstname</th>
<th class="header text-left" style="width: 10%">Gender</th>
<th class="header text-left" style="width: 10%">Age</th>
<th class="header text-center" style="width: 10%">Age</th>
<th class="header text-left" style="width: 10%">Category</th>
<th class="header text-left" style="width: 25%">Club</th>
</tr>
@ -53,7 +53,7 @@
<td class="text-left">{% if season_information.gymnast.id in request.session.available_gymnast or request.user.is_superuser %}<a href="{% url 'gymnast_details' season_information.gymnast.id %}">{% endif %}{{ season_information.gymnast.last_name }}</a></td>
<td class="text-left">{% if season_information.gymnast.id in request.session.available_gymnast or request.user.is_superuser %}<a href="{% url 'gymnast_details' season_information.gymnast.id %}">{% endif %}{{ season_information.gymnast.first_name }}</a></td>
<td class="text-left">{{ season_information.gymnast.get_gender_display }}</td>
<td class="text-left">{{ season_information.gymnast.age }}</td>
<td class="text-center">{{ season_information.gymnast.age }}</td>
<td class="text-left">{{ season_information.get_category_display }}</td>
<td class="text-left">{{ season_information.club.name }}</td>
</tr>
@ -70,15 +70,16 @@
{% block footerscript %}
<script type="text/javascript">
$(document).ready(function () {
$(function() {
$('#gymnast_table').tablesorter({
{% if request.user|has_group:"trainer" %}
headers: {
0: { sorter: false }, // disable first column
0: { sorter: false },
},
sortList: [[1, 0], [2, 0]],
sortList: [[1, 0], [2, 0]]
{% else %}
sortList: [[0, 0], [1, 0]],
sortList: [[0, 0], [1, 0]]
{% endif %}
});

View File

@ -5,7 +5,7 @@
<h4>Injuries</h4>
</div>
<div class="card-body pt-0 pb-0">
{% if injuries_list %}
{% if injury_list %}
<div class="card-body pl-0 pt-0 pr-0">
<table class="table table-striped table-condensed tablesorter mb-1">
<thead>
@ -16,7 +16,7 @@
</tr>
</thead>
<tbody>
{% for injury in injuries_list %}
{% for injury in injury_list %}
<tr>
<td class="text-left">
<a href="{% url 'injury_update' injury.id %}">
@ -51,7 +51,6 @@
headers: {
0: { sorter: false },
},
// dateFormat: "uk",
sortList: [[1, 0]]
})
});

View File

@ -51,7 +51,7 @@
<script type="text/javascript">
$(document).ready(function () {
$('#next_events').tablesorter({
dateFormat: "uk",
dateFormat : "ddmmyyyy",
headers: {
0: { sorter: false }, // disable first column
},
@ -112,7 +112,7 @@
<script type="text/javascript">
$(document).ready(function () {
$('#notes').tablesorter({
dateFormat: "uk",
dateFormat : "ddmmyyyy",
headers: {
0: { sorter: false }, // disable first column
},
@ -199,7 +199,7 @@
<script type="text/javascript">
$(document).ready(function () {
$('#previous_events').tablesorter({
dateFormat: "uk",
dateFormat : "ddmmyyyy",
headers: {
0: { sorter: false }, // disable first column
},

View File

@ -53,7 +53,7 @@
headers: {
0: { sorter: false },
},
dateFormat: "uk",
dateFormat : "ddmmyyyy",
sortList: [[1, 0],]
});

View File

@ -20,7 +20,7 @@
<!-- Fonts and icons -->
<link href="https://fonts.googleapis.com/css?family=Poppins:200,300,400,600,700,800" rel="stylesheet" />
<!-- Font Awesome Pro -->
<link href="{% static "css/gymnast_report.css" %}" rel="stylesheet" />
<link href="{% static "css/a4_paper.css" %}" rel="stylesheet" />
<link href="{% static "css/font_awesome_all_5.15.3.css" %}" rel="stylesheet" />
<link href="{% static "css/black-dashboard_report.css" %}" rel="stylesheet" />
</head>

View File

@ -17,10 +17,9 @@
<title>{{ gymnast.first_name }} {{ gymnast.last_name }}</title>
<!-- Fonts and icons -->
<link href="https://fonts.googleapis.com/css?family=Poppins:200,300,400,600,700,800" rel="stylesheet" />
<!-- Font Awesome Pro -->
<link href="{% static "css/gymnast_report.css" %}" rel="stylesheet" />
<link href="{% static "css/a4_paper.css" %}" rel="stylesheet" />
<link href="{% static "css/font_awesome_all_5.15.3.css" %}" rel="stylesheet" />
<link href="{% static "css/black-dashboard_report.css" %}" rel="stylesheet" />
</head>
@ -213,8 +212,8 @@
</div>
<div class="row">
<div class="col-12">
<h4 class="mb-1">Injury</h4>
{% if injuries_list %}
<h4 class="mb-1">Injury {% if injury_list %}({{ injury_list.count }}){% endif %}</h4>
{% if injury_list %}
<table class="table" id="injury_table">
<thead class="text-primary">
<tr>
@ -228,12 +227,12 @@
</tr>
</thead>
<tbody>
{% for injury in injuries_list %}
{% for injury in injury_list %}
<tr role="row" class="{% cycle 'odd' 'even' %}">
<td class="text-left">{{ injury.date | date:"d-m-Y" }}</td>
<td class="text-left">{{ injury.gymnast }}</td>
<td class="text-left">{{ injury.get_mechanism_display }}</td>
<td class="text-left">{{ injury.location }}</td>
<td class="text-left">{{ injury.get_location_display }}</td>
<td class="text-left">{{ injury.get_body_side_display }}</td>
<td class="text-left">
{% if injury.skill %}
@ -242,7 +241,7 @@
-
{% endif %}
</td>
<td class="text-right">
<td class="text-left">
{% if injury.nb_week_off %}
{{ injury.nb_week_off }}
{% else %}

View File

@ -20,7 +20,7 @@
<!-- Fonts and icons -->
<link href="https://fonts.googleapis.com/css?family=Poppins:200,300,400,600,700,800" rel="stylesheet" />
<!-- Font Awesome Pro -->
<link href="{% static "css/gymnast_report.css" %}" rel="stylesheet" />
<link href="{% static "css/a4_paper.css" %}" rel="stylesheet" />
<link href="{% static "css/font_awesome_all_5.15.3.css" %}" rel="stylesheet" />
<link href="{% static "css/black-dashboard_report.css" %}" rel="stylesheet" />
</head>

View File

@ -20,7 +20,7 @@
<!-- Fonts and icons -->
<link href="https://fonts.googleapis.com/css?family=Poppins:200,300,400,600,700,800" rel="stylesheet" />
<!-- Font Awesome Pro -->
<link href="{% static "css/gymnast_report.css" %}" rel="stylesheet" />
<link href="{% static "css/a4_paper.css" %}" rel="stylesheet" />
<link href="{% static "css/font_awesome_all_5.15.3.css" %}" rel="stylesheet" />
<link href="{% static "css/black-dashboard_report.css" %}" rel="stylesheet" />
</head>

View File

@ -1,8 +1,8 @@
{% load has_group %}
<div class="row justify-content-center ml-1">
<div class="col-12">
<div class="card mb-4">
<div class="row justify-content-center">
<div class="col-12 pl-0">
<div class="card mb-2">
<div class="card-header">
<h4>Documents</h4>
</div>

View File

@ -1,79 +1,94 @@
{% load static %}
<div class="row justify-content-center ml-1">
<div class="col-md-6">
<div class="card mb-4">
<div class="card-header">
<h4>Height/Weight</h4>
<div class="row justify-content-center">
<div class="col-md-6 pl-0">
<div class="card mb-3">
<div class="card-header row">
<div class="col-8">
<h4>Height/Weight</h4>
</div>
<div class="col-4 text-right">
<h3 class="mb-0">
{% if height_weight_list %}
<a href="{% url 'heightweight_list_for_gymnast' gymnast_id %}">
<i class="far fa-weight text-warning"></i>
</a>
{% endif %}
&nbsp;
<a href="{% url 'heightweight_create_for_gymnast' gymnast_id %}">
<i class="fas fa-plus text-warning"></i>
</a>
</h3>
</div>
</div>
<div class="card-body pt-0 pb-0 pr-0 pl-0">
<div class="card-body pt-0 pr-0 pl-0">
{% if height_weight_list %}
<div><canvas id="chart_height_weight" class="chartjs" width="400" height="200"></canvas></div>
<div><canvas id="chart_height_weight" class="chartjs"></canvas></div>
{% else %}
<p class="pl-3 text-muted">No height/weight recorded for this gymnast.</p>
{% endif %}
</div>
<div class="card-footer text-right text-muted pt-0">
{% if height_weight_list %}
<a href="{% url 'heightweight_list_for_gymnast' gymnast_id %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fal fa-line-height"></i>
</button>
</a>
{% endif %}
<a href="{% url 'heightweight_create_for_gymnast' gymnast_id %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fas fa-plus"></i>
</button>
</a>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card mb-4">
<div class="card-header">
<h4>Well Being</h4>
<div class="col-md-6 pl-0">
<div class="card mb-3">
<div class="card-header row">
<div class="col-8">
<h4>Well Being</h4>
</div>
<div class="col-4 text-right">
<h3 class="mb-0">
{% if wellbeing_list %}
<a href="{% url 'wellbeing_list_for_gymnast' gymnast_id %}">
<i class="far fa-file-medical-alt text-warning"></i>
</a>
{% endif %}
&nbsp;
<a href="{% url 'wellbeing_create_for_gymnast' gymnast_id %}">
<i class="fas fa-plus text-warning"></i>
</a>
</h3>
</div>
</div>
<div class="card-body pt-0 pb-0 pr-0 pl-0">
<div class="card-body pt-0 pr-0 pl-0">
{% if wellbeing_list %}
<div><canvas id="chart_wellbeing" class="chartjs" width="400" height="200"></canvas></div>
<div><canvas id="chart_wellbeing" class="chartjs"></canvas></div>
{% else %}
<p class="pl-3 text-muted">No well being recorded for this gymnast.</p>
{% endif %}
</div>
<div class="card-footer text-right text-muted pt-0">
{% if wellbeing_list %}
<a href="{% url 'wellbeing_list_for_gymnast' gymnast_id %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fal fa-file-medical-alt"></i>
</button>
</a>
{% endif %}
<a href="{% url 'wellbeing_create_for_gymnast' gymnast_id %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fas fa-plus"></i>
</button>
</a>
</div>
</div>
</div>
</div>
<div class="row justify-content-center ml-1">
<div class="col-md-12">
<div class="row justify-content-center">
<div class="col-md-12 pl-0">
<div class="card">
<div class="card-header">
<h4>Injuries ({{ number_of_injuries }})</h4>
<div class="card-header row">
<div class="col-8">
<h4>Injuries <i>on last two month ({{ injury_list.count }})</i></h4>
</div>
<div class="col-4 text-right">
<h3 class="mb-0">
{% if injury_list %}
<a href="{% url 'injury_list_for_gymnast' gymnast_id %}">
<i class="far fa-comment-alt-medical text-warning"></i>
</a>
&nbsp;
{% endif %}
<a href="{% url 'injury_create_for_gymnast' gymnast_id %}">
<i class="fas fa-plus text-warning"></i>
</a>
</h3>
</div>
</div>
<div class="card-body pt-0 pb-0">
{% if injuries_list %}
<div class="card-body pt-0">
{% if injury_list %}
<table class="table tablesorter table-striped table-condensed" id="injury_table">
<thead>
<tr>
<th style="width: 2%"></th>
<th class="header text-center" style="width: 8%">Date</th>
<th class="header text-left" style="width: 8%">Mechanism</th>
<th class="header text-center" style="width: 8%">Mechanism</th>
<th class="header text-left" style="width: 27%">Type</th>
<th class="header text-left" style="width: 25%">Location</th>
<th class="header text-left" style="width: 12%">Side</th>
@ -82,7 +97,7 @@
</tr>
</thead>
<tbody>
{% for injury in injuries_list %}
{% for injury in injury_list %}
<tr>
<td class="text-left">
<a href="{% url 'injury_update' injury.id %}">
@ -90,11 +105,16 @@
</a>
</td>
<td class="text-right"><a href="{% url 'injury_details' injury.id %}">{{ injury.date | date:"d-m-Y" }}</a></td>
<td class="text-left">{{ injury.get_mechanism_display }}</td>
<td class="text-center">{{ injury.get_mechanism_display }}</td>
<td class="text-left">{{ injury.get_injury_type_display }}</td>
<td class="text-left">{{ injury.get_location_display }}</td>
<td class="text-left">{{ injury.get_body_side_display }}</td>
<td class="text-left">{% if injury.skill %}<a href="{% url 'skill_details' injury.skill.id %}">{{ injury.skill }}</a>{% else %}-{% endif %}</td>
<td class="text-left">
{% if injury.skill %}
<a href="{% url 'skill_details' injury.skill.id %}">
{{ injury.skill.notation }}
</a>
{% else %}-{% endif %}</td>
<td class="text-center">{{ injury.nb_week_off }}</td>
</tr>
{% endfor %}
@ -104,13 +124,6 @@
<p class="text-muted">No injury known for this gymnast.</p>
{% endif %}
</div>
<div class="card-footer text-right text-muted pt-0">
<a href="{% url 'injury_create_for_gymnast' gymnast_id %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fas fa-plus"></i>
</button>
</a>
</div>
</div>
</div>
</div>
@ -124,7 +137,7 @@
headers: {
0: { sorter: false },
},
dateFormat: "uk",
dateFormat : "ddmmyyyy",
sortList: [[1, 1]]
});
@ -145,6 +158,13 @@
gradient_stroke_orange.addColorStop(0.5, 'rgba(255, 159, 64, 0.2)');
gradient_stroke_orange.addColorStop(0.25, 'rgba(255, 159, 64, 0)');
var border_color_green = 'rgb(75, 192, 192)';
var gradient_stroke_green = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_green.addColorStop(1, 'rgba(75, 192, 192, 0.4)');
gradient_stroke_green.addColorStop(0.75, 'rgba(75, 192, 192, 0.3)');
gradient_stroke_green.addColorStop(0.5, 'rgba(75, 192, 192, 0.2)');
gradient_stroke_green.addColorStop(0.25, 'rgba(75, 192, 192, 0)');
var height_values = [
{% for height_weight in height_weight_list %}
{
@ -163,6 +183,15 @@
{% endfor %}
]
var bmi_value = [
{% for height_weight in height_weight_list %}
{
x: '{{ height_weight.date | date:"d-m-Y" }}',
y: '{{ height_weight.bmi }}'
},
{% endfor %}
]
var height_weight_data = {
datasets: [
{
@ -173,6 +202,7 @@
pointBackgroundColor: border_color_pink,
fill: true,
data: height_values,
hidden: true,
},
{
label: 'Height',
@ -181,7 +211,17 @@
borderColor: border_color_orange,
pointBackgroundColor: border_color_orange,
fill: true,
data: weight_values
data: weight_values,
hidden: true,
},
{
label: 'BMI',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_green,
borderColor: border_color_green,
pointBackgroundColor: border_color_green,
fill: true,
data: bmi_value,
},
],
};

View File

@ -1,359 +0,0 @@
{% load has_group %}
{% load is_user_equal_to_gymnast %}
<div class="row justify-content-center ml-1">
<div class="col-md-6">
<div class="card mb-3">
<div class="card-header">
<h4>Intensity statistics</h4>
</div>
<div class="card-body pt-0 pb-0 pr-0 pl-0">
{% if intensity_list %}
<div><canvas id="chart_intensity" class="chartjs" width="400" height="200"></canvas></div>
{% else %}
<p class="pl-3 text-muted">No intensity recorded for this gymnast.</p>
{% endif %}
</div>
<div class="card-footer text-right text-muted pt-0">
{% if intensity_list %}
<a href="{% url 'intensity_list_for_gymnast' gymnast_id %}">
<button type="submit" value="list" class="btn btn-icon btn-warning mr-2">
<i class="fal fa-analytics"></i> <!-- Routines -->
</button>
</a>
{% endif %}
{% if request.user|has_group:"trainer" or request.user|is_user_equal_to_gymnast:gymnast_id %}
<a href="{% url 'intensity_create_for_gymnast' gymnast_id %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fas fa-plus"></i>
</button>
</a>
{% endif %}
</div>
</div>
</div>
<div class="col-md-6 pl-1">
<div class="card mb-3">
<div class="card-header">
<h4>Chronos</h4>
</div>
<div class="card-body pt-0 pb-0 pr-0 pl-0">
{% if chrono_list %}
<div><canvas id="chart_chrono" class="chartjs" width="400" height="200"></canvas></div>
{% else %}
<p class="pl-3 text-muted">No chrono recorded yet for this gymnast.</p>
{% endif %}
</div>
<div class="card-footer pt-0 row">
<div class="col-md-6 text-muted pt-0">
<a href="{% url 'average_jump_chrono_details_for_gymnast' gymnast_id %}">
<button type="submit" value="add" class="btn btn-icon btn-warning mr-2">
<i class="fad fa-analytics"></i>
</button>
</a>
</div>
<div class="col-md-6 text-right text-muted pt-0">
{% if chrono_list %}
<a href="{% url 'chrono_list_for_gymnast' gymnast_id %}">
<button type="submit" value="add" class="btn btn-icon btn-warning mr-2">
<i class="fal fa-stopwatch"></i>
</button>
</a>
{% endif %}
{% if request.user|has_group:"trainer" or request.user|is_user_equal_to_gymnast:gymnast_id %}
<a href="{% url 'chrono_create_for_gymnast' gymnast_id %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fas fa-plus"></i>
</button>
</a>
{% endif %}
</div>
</div>
</div>
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h4>Training Program</h4>
</div>
<div class="card-body">
{% if date_list %}
{% for date in date_list %}
<a href="{% url 'trainingprogram_details' date gymnast_id %}">{{ date|date:"l j F Y" }}</a>
{% endfor %}
{% else %}
<p>Pas de training planifié.</p>
{% endif %}
</div>
</div>
</div>
</div>
<script type="text/javascript">
var timeFormat = 'DD-MM-YYYY';
{% if intensity_list %}
var ctx = document.getElementById('chart_intensity').getContext('2d');
var average_difficulty_by_passe = [
{% for score in intensity_list %}
{
x: '{{ score.date | date:"d-m-Y" }}',
y: '{{ score.average_difficulty_by_passe_in_unit }}'
},
{% endfor %}
];
var average_quantity_of_skill_by_time = [
{% for score in intensity_list %}
{
x: '{{ score.date | date:"d-m-Y" }}',
y: '{{ score.average_quantity_of_skill_by_time }}'
},
{% endfor %}
];
var average_quantity_of_skill_by_passe = [
{% for score in intensity_list %}
{
x: '{{ score.date | date:"d-m-Y" }}',
y: '{{ score.average_quantity_of_skill_by_passe }}'
},
{% endfor %}
];
var average_difficulty_by_skill = [
{% for score in intensity_list %}
{
x: '{{ score.date | date:"d-m-Y" }}',
y: '{{ score.average_difficulty_by_skill }}'
},
{% endfor %}
];
var score_values = {
datasets: [
{
label: 'diff/pass',
cubicInterpolationMode: 'monotone',
borderColor: 'rgb(75, 192, 192)',
pointBackgroundColor: 'rgb(75, 192, 192)',
data: average_difficulty_by_passe
},
{
label: '# skills',
cubicInterpolationMode: 'monotone',
borderColor: 'rgb(255, 99, 132)',
pointBackgroundColor: 'rgb(255, 99, 132)',
data: average_quantity_of_skill_by_time
},
{
label: '# skill/pass',
cubicInterpolationMode: 'monotone',
borderColor: 'rgb(255, 159, 64)',
pointBackgroundColor: 'rgb(255, 159, 64)',
data: average_quantity_of_skill_by_passe
},
{
label: 'diff/skill',
cubicInterpolationMode: 'monotone',
borderColor: 'rgb(54, 162, 235)',
pointBackgroundColor: 'rgb(54, 162, 235)',
data: average_difficulty_by_skill
},
],
}
new Chart(ctx, {
type: 'line',
data: score_values,
options: {
scales: {
x: {
type: 'time',
display: true,
scaleLabel: {
display: true,
labelString: 'Date',
ticks: {
autoSkip: true,
source: 'data',
},
},
time: {
parser: timeFormat,
tooltipFormat: 'LL',
round: 'day',
},
},
},
plugins: {
legend: {
display: true,
position: 'bottom',
}
}
},
});
{% endif %}
/*
red: 'rgb(255, 99, 132)',
orange: 'rgb(255, 159, 64)',
yellow: 'rgb(255, 205, 86)',
green: 'rgb(75, 192, 192)',
blue: 'rgb(54, 162, 235)',
purple: 'rgb(153, 102, 255)',
grey: 'rgb(201, 203, 207)'
http://www.chartjs.org/samples/latest/scales/time/line-point-data.html
*/
{% if chrono_list %}
var ctx = document.getElementById('chart_chrono').getContext('2d');
var gradient_stroke_1 = ctx.createLinearGradient(0, 230, 0, 50);
var gradient_stroke_2 = ctx.createLinearGradient(0, 230, 0, 50);
var gradient_stroke_3 = ctx.createLinearGradient(0, 230, 0, 50);
var gradient_stroke_4 = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_1.addColorStop(0.75, 'rgba(75, 192, 192, 0.3)');
gradient_stroke_1.addColorStop(0.5, 'rgba(75, 192, 192, 0.2)');
gradient_stroke_1.addColorStop(0.25, 'rgba(75, 192, 192, 0)');
gradient_stroke_2.addColorStop(1, 'rgba(255, 99, 132, 0.4)');
gradient_stroke_2.addColorStop(0.75, 'rgba(255, 99, 132, 0.3)');
gradient_stroke_2.addColorStop(0.5, 'rgba(255, 99, 132, 0.2)');
gradient_stroke_2.addColorStop(0.25, 'rgba(255, 99, 132, 0)');
gradient_stroke_3.addColorStop(1, 'rgba(255, 159, 64, 0.4)');
gradient_stroke_3.addColorStop(0.75, 'rgba(255, 159, 64, 0.3)');
gradient_stroke_3.addColorStop(0.5, 'rgba(255, 159, 64, 0.2)');
gradient_stroke_3.addColorStop(0.25, 'rgba(255, 159, 64, 0)');
gradient_stroke_4.addColorStop(1, 'rgba(54, 162, 235, 0.4)');
gradient_stroke_4.addColorStop(0.75, 'rgba(54, 162, 235, 0.3)');
gradient_stroke_4.addColorStop(0.5, 'rgba(54, 162, 235, 0.2)');
gradient_stroke_4.addColorStop(0.25, 'rgba(54, 162, 235, 0)');
var straightjump_values = [
{% for chrono in chrono_10c %}
{
x: '{{ chrono.date | date:"d-m-Y" }}',
y: '{{ chrono.score_avg | floatformat:3 }}'
},
{% endfor %}
];
var compulsory_routine_values = [
{% for chrono in chrono_r1 %}
{
x: '{{ chrono.date | date:"d-m-Y" }}',
y: '{{ chrono.score_avg | floatformat:3 }}'
},
{% endfor %}
];
var volontary_routine_values = [
{% for chrono in chrono_r2 %}
{
x: '{{ chrono.date | date:"d-m-Y" }}',
y: '{{ chrono.score_avg | floatformat:3 }}'
},
{% endfor %}
];
var final_routine_values = [
{% for chrono in chrono_rf %}
{
x: '{{ chrono.date | date:"d-m-Y" }}',
y: '{{ chrono.score_avg | floatformat:3 }}'
},
{% endfor %}
];
var chrono_values = {
datasets: [
{% if chrono_10c %}
{
label: '10 |',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_1,
borderColor: 'rgb(75, 192, 192)',
pointBackgroundColor: 'rgb(75, 192, 192)',
fill: true,
data: straightjump_values,
},
{% endif %}
{% if chrono_r1 %}
{
label: 'Q1R1',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_2,
borderColor: 'rgb(255, 99, 132)',
pointBackgroundColor: 'rgb(255, 99, 132)',
fill: true,
data: compulsory_routine_values,
},
{% endif %}
{% if chrono_r2 %}
{
label: 'Q1R2',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_3,
borderColor: 'rgb(255, 159, 64)',
pointBackgroundColor: 'rgb(255, 159, 64)',
fill: true,
data: volontary_routine_values,
},
{% endif %}
{% if chrono_rf %}
{
label: 'Q2R1',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_4,
borderColor: 'rgb(255, 205, 86)',
pointBackgroundColor: 'rgb(255, 205, 86)',
fill: true,
data: final_routine_values,
},
{% endif %}
]
}
new Chart(ctx, {
type: 'line',
data: chrono_values,
options: {
scales: {
x: {
type: 'time',
display: true,
scaleLabel: {
display: true,
labelString: 'Date',
ticks: {
autoSkip: true,
source: 'data',
},
},
time: {
parser: timeFormat,
tooltipFormat: 'LL',
round: 'day',
},
},
},
plugins: {
legend: {
display: true,
position: 'bottom',
}
}
},
});
{% endif %}
</script>

View File

@ -0,0 +1,414 @@
{% load has_group %}
{% load is_user_equal_to_gymnast %}
<div class="row justify-content-center">
<div class="col-md-6 pl-0">
<div class="card mb-3">
<div class="card-header row">
<div class="col-8">
<h4>Intensity statistics</h4>
</div>
<div class="col-4 text-right">
<h3 class="mb-0">
{% if intensity_list %}
<a href="{% url 'intensity_list_for_gymnast' gymnast_id %}">
<i class="fal fa-analytics text-warning"></i>
</a>
{% endif %}
&nbsp;
{% if request.user|has_group:"trainer" or request.user|is_user_equal_to_gymnast:gymnast_id %}
<a href="{% url 'intensity_create_for_gymnast' gymnast_id %}">
<i class="fas fa-plus text-warning"></i>
</a>
{% endif %}
</h3>
</div>
</div>
<div class="card-body pt-0 pr-0 pl-0">
{% if intensity_list %}
<div><canvas id="chart_intensity" class="chartjs" width="400" height="200"></canvas></div>
{% else %}
<p class="pl-3 text-muted">No intensity recorded for this gymnast.</p>
{% endif %}
</div>
</div>
</div>
<div class="col-md-6 pl-1">
<div class="card mb-3">
<div class="card-header row">
<div class="col-8">
<h4>Chronos</h4>
</div>
<div class="col-4 text-right">
<h3 class="mb-0">
{% if chrono_list %}
<a href="{% url 'chrono_list_for_gymnast' gymnast_id %}">
<i class="fal fa-stopwatch text-warning"></i>
</a>
{% endif %}
&nbsp;
{% if request.user|has_group:"trainer" or request.user|is_user_equal_to_gymnast:gymnast_id %}
<a href="{% url 'chrono_create_for_gymnast' gymnast_id %}">
<i class="fas fa-plus text-warning"></i>
</a>
{% endif %}
</h3>
</div>
</div>
<div class="card-body pt-0 pb-0 pr-0 pl-0">
{% if chrono_list %}
<div><canvas id="chart_chrono" class="chartjs" width="400" height="200"></canvas></div>
{% else %}
<p class="pl-3 text-muted">No chrono recorded yet for this gymnast.</p>
{% endif %}
</div>
<div class="card-footer pt-0 row">
<div class="col-12 text-right pt-0">
<h3 class="mb-0">
<a href="{% url 'average_jump_chrono_details_for_gymnast' gymnast_id %}">
<i class="fad fa-analytics text-warning"></i>
</a>
</h3>
</div>
</div>
</div>
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h4>Training Program</h4>
</div>
<div class="card-body pt-0">
{% if date_list %}
{% for date in date_list %}
<a href="{% url 'trainingprogram_details' date gymnast_id %}">{{ date|date:"l j F Y" }}</a>
{% endfor %}
{% else %}
<p class="text-muted">Pas de training planifié.</p>
{% endif %}
</div>
</div>
</div>
</div>
<script type="text/javascript">
var timeFormat = 'DD-MM-YYYY';
{% if intensity_list %}
var ctx = document.getElementById('chart_intensity').getContext('2d');
var border_color_pink = 'rgb(255, 99, 132)';
var gradient_stroke_pink = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_pink.addColorStop(1, 'rgba(255, 99, 132, 0.4)');
gradient_stroke_pink.addColorStop(0.75, 'rgba(255, 99, 132, 0.3)');
gradient_stroke_pink.addColorStop(0.5, 'rgba(255, 99, 132, 0.2)');
gradient_stroke_pink.addColorStop(0.25, 'rgba(255, 99, 132, 0)');
var border_color_orange = 'rgb(255, 159, 64)';
var gradient_stroke_orange = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_orange.addColorStop(1, 'rgba(255, 159, 64, 0.4)');
gradient_stroke_orange.addColorStop(0.75, 'rgba(255, 159, 64, 0.3)');
gradient_stroke_orange.addColorStop(0.5, 'rgba(255, 159, 64, 0.2)');
gradient_stroke_orange.addColorStop(0.25, 'rgba(255, 159, 64, 0)');
var border_color_green = 'rgb(75, 192, 192)';
var gradient_stroke_green = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_green.addColorStop(1, 'rgba(75, 192, 192, 0.4)');
gradient_stroke_green.addColorStop(0.75, 'rgba(75, 192, 192, 0.3)');
gradient_stroke_green.addColorStop(0.5, 'rgba(75, 192, 192, 0.2)');
gradient_stroke_green.addColorStop(0.25, 'rgba(75, 192, 192, 0)');
var border_color_blue = 'rgb(54, 162, 235)';
var gradient_stroke_blue = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_blue.addColorStop(1, 'rgba(54, 162, 235, 0.4)');
gradient_stroke_blue.addColorStop(0.75, 'rgba(54, 162, 235, 0.3)');
gradient_stroke_blue.addColorStop(0.5, 'rgba(54, 162, 235, 0.2)');
gradient_stroke_blue.addColorStop(0.25, 'rgba(54, 162, 235, 0)');
var border_color_yellow = 'rgb(255, 205, 86)';
var gradient_stroke_yellow = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_yellow.addColorStop(1, 'rgba(255, 205, 86, 0.4)');
gradient_stroke_yellow.addColorStop(0.75, 'rgba(255, 205, 86, 0.3)');
gradient_stroke_yellow.addColorStop(0.5, 'rgba(255, 205, 86, 0.2)');
gradient_stroke_yellow.addColorStop(0.25, 'rgba(255, 205, 86, 0)');
var average_difficulty_by_passe = [
{% for score in intensity_list %}
{
x: '{{ score.date | date:"d-m-Y" }}',
y: '{{ score.average_difficulty_by_passe_in_unit }}'
},
{% endfor %}
];
var average_quantity_of_skill_by_time = [
{% for score in intensity_list %}
{
x: '{{ score.date | date:"d-m-Y" }}',
y: '{{ score.average_quantity_of_skill_by_time }}'
},
{% endfor %}
];
var average_quantity_of_skill_by_passe = [
{% for score in intensity_list %}
{
x: '{{ score.date | date:"d-m-Y" }}',
y: '{{ score.average_quantity_of_skill_by_passe }}'
},
{% endfor %}
];
var average_difficulty_by_skill = [
{% for score in intensity_list %}
{
x: '{{ score.date | date:"d-m-Y" }}',
y: '{{ score.average_difficulty_by_skill }}'
},
{% endfor %}
];
var score_values = {
datasets: [
{
label: 'diff/pass',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_pink,
borderColor: border_color_pink,
pointBackgroundColor: border_color_pink,
fill: true,
data: average_difficulty_by_passe
},
{
label: '# skills',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_orange,
borderColor: border_color_orange,
pointBackgroundColor: border_color_orange,
fill: true,
data: average_quantity_of_skill_by_time
},
{
label: '# skill/pass',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_green,
borderColor: border_color_green,
pointBackgroundColor: border_color_green,
fill: true,
data: average_quantity_of_skill_by_passe
},
{
label: 'diff/skill',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_blue,
borderColor: border_color_blue,
pointBackgroundColor: border_color_blue,
fill: true,
data: average_difficulty_by_skill
},
],
}
new Chart(ctx, {
type: 'line',
data: score_values,
options: {
scales: {
x: {
type: 'time',
display: true,
scaleLabel: {
display: true,
labelString: 'Date',
ticks: {
autoSkip: true,
source: 'data',
},
},
time: {
parser: timeFormat,
tooltipFormat: 'LL',
round: 'day',
},
},
},
plugins: {
legend: {
display: true,
position: 'bottom',
}
}
},
});
{% endif %}
/*
red: 'rgb(255, 99, 132)',
orange: 'rgb(255, 159, 64)',
yellow: 'rgb(255, 205, 86)',
green: 'rgb(75, 192, 192)',
blue: 'rgb(54, 162, 235)',
purple: 'rgb(153, 102, 255)',
grey: 'rgb(201, 203, 207)'
http://www.chartjs.org/samples/latest/scales/time/line-point-data.html
*/
{% if chrono_list %}
var ctx = document.getElementById('chart_chrono').getContext('2d');
var border_color_pink = 'rgb(255, 99, 132)';
var gradient_stroke_pink = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_pink.addColorStop(1, 'rgba(255, 99, 132, 0.4)');
gradient_stroke_pink.addColorStop(0.75, 'rgba(255, 99, 132, 0.3)');
gradient_stroke_pink.addColorStop(0.5, 'rgba(255, 99, 132, 0.2)');
gradient_stroke_pink.addColorStop(0.25, 'rgba(255, 99, 132, 0)');
var border_color_orange = 'rgb(255, 159, 64)';
var gradient_stroke_orange = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_orange.addColorStop(1, 'rgba(255, 159, 64, 0.4)');
gradient_stroke_orange.addColorStop(0.75, 'rgba(255, 159, 64, 0.3)');
gradient_stroke_orange.addColorStop(0.5, 'rgba(255, 159, 64, 0.2)');
gradient_stroke_orange.addColorStop(0.25, 'rgba(255, 159, 64, 0)');
var border_color_green = 'rgb(75, 192, 192)';
var gradient_stroke_green = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_green.addColorStop(1, 'rgba(75, 192, 192, 0.4)');
gradient_stroke_green.addColorStop(0.75, 'rgba(75, 192, 192, 0.3)');
gradient_stroke_green.addColorStop(0.5, 'rgba(75, 192, 192, 0.2)');
gradient_stroke_green.addColorStop(0.25, 'rgba(75, 192, 192, 0)');
var border_color_blue = 'rgb(54, 162, 235)';
var gradient_stroke_blue = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_blue.addColorStop(1, 'rgba(54, 162, 235, 0.4)');
gradient_stroke_blue.addColorStop(0.75, 'rgba(54, 162, 235, 0.3)');
gradient_stroke_blue.addColorStop(0.5, 'rgba(54, 162, 235, 0.2)');
gradient_stroke_blue.addColorStop(0.25, 'rgba(54, 162, 235, 0)');
var border_color_yellow = 'rgb(255, 205, 86)';
var gradient_stroke_yellow = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_yellow.addColorStop(1, 'rgba(255, 205, 86, 0.4)');
gradient_stroke_yellow.addColorStop(0.75, 'rgba(255, 205, 86, 0.3)');
gradient_stroke_yellow.addColorStop(0.5, 'rgba(255, 205, 86, 0.2)');
gradient_stroke_yellow.addColorStop(0.25, 'rgba(255, 205, 86, 0)');
var straightjump_values = [
{% for chrono in chrono_10c %}
{
x: '{{ chrono.date | date:"d-m-Y" }}',
y: '{{ chrono.score_avg | floatformat:3 }}'
},
{% endfor %}
];
var compulsory_routine_values = [
{% for chrono in chrono_r1 %}
{
x: '{{ chrono.date | date:"d-m-Y" }}',
y: '{{ chrono.score_avg | floatformat:3 }}'
},
{% endfor %}
];
var volontary_routine_values = [
{% for chrono in chrono_r2 %}
{
x: '{{ chrono.date | date:"d-m-Y" }}',
y: '{{ chrono.score_avg | floatformat:3 }}'
},
{% endfor %}
];
var final_routine_values = [
{% for chrono in chrono_rf %}
{
x: '{{ chrono.date | date:"d-m-Y" }}',
y: '{{ chrono.score_avg | floatformat:3 }}'
},
{% endfor %}
];
var chrono_values = {
datasets: [
{% if chrono_10c %}
{
label: '10 |',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_pink,
borderColor: border_color_pink,
pointBackgroundColor: border_color_pink,
fill: true,
data: straightjump_values,
},
{% endif %}
{% if chrono_r1 %}
{
label: 'Q1R1',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_orange,
borderColor: border_color_orange,
pointBackgroundColor: border_color_orange,
fill: true,
data: compulsory_routine_values,
},
{% endif %}
{% if chrono_r2 %}
{
label: 'Q1R2',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_green,
borderColor: border_color_green,
pointBackgroundColor: border_color_green,
fill: true,
data: volontary_routine_values,
},
{% endif %}
{% if chrono_rf %}
{
label: 'Q2R1',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_blue,
borderColor: border_color_blue,
pointBackgroundColor: border_color_blue,
fill: true,
data: final_routine_values,
},
{% endif %}
]
}
new Chart(ctx, {
type: 'line',
data: chrono_values,
options: {
scales: {
x: {
type: 'time',
display: true,
scaleLabel: {
display: true,
labelString: 'Date',
ticks: {
autoSkip: true,
source: 'data',
},
},
time: {
parser: timeFormat,
tooltipFormat: 'LL',
round: 'day',
},
},
},
plugins: {
legend: {
display: true,
position: 'bottom',
}
}
},
});
{% endif %}
</script>

View File

@ -1,40 +1,49 @@
{% load has_group %}
{% if latest_published_note %}
<div class="row justify-content-center ml-1">
<div class="col-md-12">
<div class="card">
<div class="row justify-content-center">
<div class="col-md-12 pl-0">
<div class="card mb-3">
<div class="card-header">
<h4 class="mb-0">{{ latest_published_note.title }}</h4>
<p class="text-muted">{{ latest_published_note.date | date:'j N Y' }}</p>
<div class="row">
<div class="col-8">
<h4 class="mb-0">{{ latest_published_note.title }}</h4>
<p class="text-muted">{{ latest_published_note.date | date:'j N Y' }}</p>
</div>
{% if request.user.id == latest_published_note.coach.id %}
<div class="col-1 ml-auto text-right">
<h3><a href="{% url 'note_update' latest_published_note.id %}">
<span class="far fa-pencil text-warning"></span>
</a></h3>
</div>
{% endif %}
</div>
</div>
<div class="card-body pt-0">
<div class="card-body pt-0 text-justify">
<p>{{ latest_published_note.to_markdown | safe }}</p>
</div>
<div class="card-footer text-right text-muted pt-0">
{% if request.user.id == latest_published_note.coach.id %}
<a href="{% url 'note_update' latest_published_note.id %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<span class="tim-icons icon-pencil"></span>
</button>
</a>
{% endif %}
</div>
</div>
</div>
</div>
{% endif %}
<div class="row justify-content-center ml-1">
<div class="col-md-6">
<div class="row justify-content-center">
<div class="col-md-6 pl-0">
<div class="card">
<div class="card-header">
<h4>Next events</h4>
<div class="card-header row">
<div class="col-8">
<h4>Next events</h4>
</div>
<div class="col-4 text-right">
<h3 class="mb-0"><a href="{% url 'event_list_for_gymnast' gymnast_id %}">
<i class="far fa-calendar-alt text-warning"></i>
</a></h3>
</div>
</div>
<div class="card-body pt-0 pb-0 pr-1 pl-1">
<div class="card-body mb-0">
{% if next_event_list %}
<table class="table tablesorter table-condensed table-striped" id="next_events">
<table class="table tablesorter table-condensed table-striped mb-0" id="next_events">
<thead>
<tr>
<th style="width: 25%" class='header text-left'>Name</th>
@ -61,20 +70,35 @@
</tbody>
</table>
{% else %}
<p class="pl-2 pb-3 text-muted">No next event associated to this gymnast.</p>
<p class="text-muted">No next event associated to this gymnast.</p>
{% endif %}
</div>
</div>
</div>
<div class="col-md-6">
<div class="col-md-6 pl-0">
<div class="card">
<div class="card-header">
<h4>Last notes</h4>
<div class="card-header row">
<div class="col-8">
<h4>Last notes</h4>
</div>
<div class="col-4 text-right">
<h3 class="mb-0">
<a href="{% url 'note_list_for_gymnast' gymnast_id %}">
<i class="far fa-comment-alt-lines text-warning"></i>
</a>
{% if request.user|has_group:"trainer" %}
&nbsp;
<a href="{% url 'note_create_for_gymnast' gymnast_id %}">
<i class="fas fa-plus text-warning"></i>
</a>
{% endif %}
</h3>
</div>
</div>
<div class="card-body pt-0 pb-0 pr-1 pl-1">
<div class="card-body pr-1 pl-1">
{% if last_notes_list %}
<table class="table tablesorter table-condensed table-striped" id="notes">
<table class="table tablesorter table-condensed table-striped mb-0" id="notes">
<thead>
<tr>
<th style="width: 4%"></th>
@ -92,8 +116,13 @@
</a>
</td>
<td class="text-right">
{% if not note.status %}<span class="text-danger">{{ note.date | date:"j-m-Y" }}</span>
{% else %}{{ note.date | date:"j-m-Y" }}{% endif %}
{% if not note.status %}
<span class="text-danger">
{{ note.date | date:"j-m-Y" }}
</span>
{% else %}
{{ note.date | date:"j-m-Y" }}
{% endif %}
&nbsp;
</td>
@ -109,15 +138,6 @@
<p class="pl-2 text-muted">No note for this gymnast.</p>
{% endif %}
</div>
<div class="card-footer text-right text-muted pt-0">
{% if request.user|has_group:"trainer" %}
<a href="{% url 'note_create_for_gymnast' gymnast_id %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fas fa-plus"></i>
</button>
</a>
{% endif %}
</div>
</div>
</div>
</div>
@ -167,7 +187,7 @@
<script type="text/javascript">
$(document).ready(function(){
$('#next_events').tablesorter({
dateFormat: "uk",
dateFormat : "ddmmyyyy",
headers: {
0: { sorter: false },
},
@ -175,7 +195,7 @@
});
$('#notes').tablesorter({
dateFormat: "uk",
dateFormat : "ddmmyyyy",
headers: {
0: { sorter: false },
},
@ -184,7 +204,7 @@
{% if previous_events %}
$('#previous_events').tablesorter({
dateFormat: "uk",
dateFormat : "ddmmyyyy",
headers: {
0: { sorter: false },
},

View File

@ -1,45 +1,61 @@
{% load has_group %}
{% load is_user_equal_to_gymnast %}
<div class="row justify-content-center ml-1">
<div class="col-md-6">
<div class="card mb-4">
<div class="card-header">
<h4>Scores</h4>
<div class="row justify-content-center">
<div class="col-md-6 pl-0">
<div class="card mb-3">
<div class="card-header row">
<div class="col-8">
<h4>Scores</h4>
</div>
<div class="col-4 text-right">
<h3 class="mb-0">
{% if score_list %}
<a href="{% url 'score_list_for_gymnast' gymnast_id %}">
<i class="fal fa-crosshairs text-warning"></i>
</a>
{% endif %}
&nbsp;
{% if request.user|has_group:"trainer" or request.user|is_user_equal_to_gymnast:gymnast_id %}
<a href="{% url 'score_create_for_gymnast' gymnast_id %}">
<i class="fas fa-plus text-warning"></i>
</a>
{% endif %}
</h3>
</div>
</div>
<div class="card-body pt-0 pb-0 pr-0 pl-0">
<div class="card-body pt-0 pr-0 pl-0">
{% if score_list %}
<div><canvas id="chart_score_competition" class="chartjs" width="400" height="200"></canvas></div>
{% else %}
<p class="pl-3 text-muted">No score recorded for this gymnast.</p>
{% endif %}
</div>
<div class="card-footer text-right text-muted pt-0">
{% if score_list %}
<a href="{% url 'score_list_for_gymnast' gymnast_id %}">
<button type="submit" value="add" class="btn btn-icon btn-warning mr-2">
<i class="fal fa-crosshairs"></i>
</button>
</a>
{% endif %}
{% if request.user|has_group:"trainer" or request.user|is_user_equal_to_gymnast:gymnast_id %}
<a href="{% url 'score_create_for_gymnast' gymnast_id %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fas fa-plus"></i>
</button>
</a>
{% endif %}
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h4>Routine's statistics</h4>
<div class="col-md-6 pl-0">
<div class="card mb-3">
<div class="card-header row">
<div class="col-8">
<h4>Routine's statistics</h4>
</div>
<div class="col-4 text-right">
<h3 class="mb-0">
{% if routine_one_done_list or routine_two_done_list %}
<a href="{% url 'routinedone_list_for_gymnast' gymnast_id %}">
<i class="far fa-chart-bar text-warning"></i>
</a>
{% endif %}
{% if request.user|has_group:"trainer" or request.user|is_user_equal_to_gymnast:gymnast_id %}
<a href="{% url 'routinedone_create_for_gymnast' gymnast_id %}">
<i class="fas fa-plus text-warning"></i>
</a>
{% endif %}
</h3>
</div>
</div>
<div class="card-body pt-0 pb-0 pr-0 pl-0">
<div class="card-body p-0">
{% if routine_one_done_list or routine_two_done_list %}
<div><canvas id="chart_routine_done" class="chartjs" width="400" height="200"></canvas></div>
{% else %}
@ -48,7 +64,7 @@
</div>
<div class="card-footer pt-0 row">
{% if ghr_list %}
<div class="col-md-6 text-muted pt-0">
<div class="col-md-6 pt-0">
{% if has_routine_1 %}
<a href="#">
<button type="submit" value="list" class="btn btn-icon btn-success mr-2 action-button"
@ -65,7 +81,8 @@
</button>
</a>
{% endif %}
&nbsp;&nbsp;
</div>
<div class="col-md-6 text-right pt-0 pr-2">
{% if has_routine_1 %}
<a href="#">
<button type="submit" value="list" class="btn btn-icon btn-danger mr-2 action-button"
@ -84,32 +101,36 @@
{% endif %}
</div>
{% endif %}
<div class="col-md-6 {% if not ghr_list %}offset-md-6{% endif %} text-right text-muted pt-0">
{% if routine_one_done_list or routine_two_done_list %}
<a href="{% url 'routinedone_list_for_gymnast' gymnast_id %}">
<button type="submit" value="list" class="btn btn-icon btn-warning mr-2">
<i class="far fa-chart-bar"></i>
</button>
</a>
{% endif %}
{% if request.user|has_group:"trainer" or request.user|is_user_equal_to_gymnast:gymnast_id %}
<a href="{% url 'routinedone_create_for_gymnast' gymnast_id %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fas fa-plus"></i>
</button>
</a>
{% endif %}
</div>
</div>
</div>
</div>
<div class="col-md-12">
</div>
<div class="row justify-content-center">
<div class="col-md-12 pl-0">
<div class="card">
<div class="card-header">
<h4>Active routines</h4>
<div class="card-header row">
<div class="col-8">
<h4>Active routines</h4>
</div>
<div class="col-4 text-right">
<h3 class="mb-0">
{% if ghr_list %}
<a href="{% url 'routine_list_for_gymnast' gymnast_id %}">
<i class="tim-icons icon-components text-warning"></i>
</a>
{% endif %}
{% if request.user|has_group:"trainer" or request.user|is_user_equal_to_gymnast:gymnast_id %}
&nbsp;
<a href="{% url 'link_routine_to_gymnast' gymnast_id %}">
<i class="fas fa-plus text-warning"></i>
</a>
{% endif %}
</h3>
</div>
</div>
<div class="card-body pt-0 pb-0 pr-0 pl-0">
<div class="card-body pt-0 pr-0 pl-0">
{% if ghr_list %}
<div class="pr-1 pl-1">
<table class="table tablesorter table-striped table-condensed" data-sort="table" id="routine_table">
@ -119,19 +140,19 @@
<th style="width: 30%" class="header text-left">Label</th>
<th style="width: 15%" class="header text-left">From</th>
<th style="width: 10%" class="header text-center">Diff.</th>
<th style="width: 10%" class="header text-center">Level</th>
<th style="width: 10%" class="header text-center">Rank</th>
</tr>
</thead>
<tbody>
{% for ghr in ghr_list %}
<tr>
<td class="text-center">{{ ghr.get_routine_type_display }}</td>
<td class="text-left"><a href="{% url 'combination_details' ghr.routine.id %}">{{ ghr.routine.short_label }}</a></td>
<td class="text-left">
<a href="{% url 'combination_details' ghr.routine.id %}">
{{ ghr.routine.short_label }}
</a>
</td>
<td class="text-center">{{ ghr.date_begin | date:"d-m-Y"}}</td>
<td class="text-center"><b>{{ ghr.routine.difficulty }}</b></td>
<td class="text-center">{{ ghr.routine.level }}</td>
<td class="text-center">{{ ghr.routine.rank }}</td>
</tr>
{% endfor %}
</tbody>
@ -141,23 +162,6 @@
<p class="pl-3 text-muted">There are no routines associated to this gymnast.</p>
{% endif %}
</div>
<div class="card-footer text-right text-muted pt-0">
{% if ghr_list %}
<a href="{% url 'routine_list_for_gymnast' gymnast_id %}">
<button type="submit" value="list" class="btn btn-icon btn-warning mr-2">
<i class="tim-icons icon-components"></i> <!-- Routines -->
</button>
</a>
{% endif %}
{% if request.user|has_group:"trainer" or request.user|is_user_equal_to_gymnast:gymnast_id %}
<a href="{% url 'link_routine_to_gymnast' gymnast_id %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fas fa-plus"></i>
</button>
</a>
{% endif %}
</div>
</div>
</div>
</div>
@ -165,18 +169,12 @@
<script type="text/javascript">
$(document).ready(function () {
$('#routine_table').tablesorter({
// headers: {
// 0: { sorter: false }, // disable first column
// },
dateFormat: "uk",
dateFormat : "ddmmyyyy",
sortList: [[0, 0],]
});
$('#stats_table').tablesorter({
// headers: {
// 0: { sorter: false }, // disable first column
// },
dateFormat: "uk",
dateFormat : "ddmmyyyy",
sortList: [[0, 1],]
});
@ -191,10 +189,7 @@
csrfmiddlewaretoken: '{{ csrf_token }}'
},
}).done(function () {
//
// RELOAD DE L'ONGLET
//
//
location.reload(); // recharge TOUTE la page... Overkill !
// tab_url = {% url 'gymnast_details_tab' gymnast_id 'routine' %};
// tab_div = '#routine';
@ -221,20 +216,26 @@
var gradient_stroke_2 = ctx.createLinearGradient(0, 230, 0, 50);
var gradient_stroke_3 = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_1.addColorStop(1, 'rgba(255, 99, 132, 0.4)');
gradient_stroke_1.addColorStop(0.75, 'rgba(255, 99, 132, 0.3)');
gradient_stroke_1.addColorStop(0.5, 'rgba(255, 99, 132, 0.2)');
gradient_stroke_1.addColorStop(0.25, 'rgba(255, 99, 132, 0)');
var border_color_pink = 'rgb(255, 99, 132)';
var gradient_stroke_pink = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_pink.addColorStop(1, 'rgba(255, 99, 132, 0.4)');
gradient_stroke_pink.addColorStop(0.75, 'rgba(255, 99, 132, 0.3)');
gradient_stroke_pink.addColorStop(0.5, 'rgba(255, 99, 132, 0.2)');
gradient_stroke_pink.addColorStop(0.25, 'rgba(255, 99, 132, 0)');
gradient_stroke_2.addColorStop(1, 'rgba(255, 159, 64, 0.4)');
gradient_stroke_2.addColorStop(0.75, 'rgba(255, 159, 64, 0.3)');
gradient_stroke_2.addColorStop(0.5, 'rgba(255, 159, 64, 0.2)');
gradient_stroke_2.addColorStop(0.25, 'rgba(255, 159, 64, 0)');
var border_color_orange = 'rgb(255, 159, 64)';
var gradient_stroke_orange = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_orange.addColorStop(1, 'rgba(255, 159, 64, 0.4)');
gradient_stroke_orange.addColorStop(0.75, 'rgba(255, 159, 64, 0.3)');
gradient_stroke_orange.addColorStop(0.5, 'rgba(255, 159, 64, 0.2)');
gradient_stroke_orange.addColorStop(0.25, 'rgba(255, 159, 64, 0)');
gradient_stroke_3.addColorStop(1, 'rgba(54, 162, 235, 0.4)');
gradient_stroke_3.addColorStop(0.75, 'rgba(54, 162, 235, 0.3)');
gradient_stroke_3.addColorStop(0.5, 'rgba(54, 162, 235, 0.2)');
gradient_stroke_3.addColorStop(0.25, 'rgba(54, 162, 235, 0)');
var border_color_green = 'rgb(75, 192, 192)';
var gradient_stroke_green = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_green.addColorStop(1, 'rgba(75, 192, 192, 0.4)');
gradient_stroke_green.addColorStop(0.75, 'rgba(75, 192, 192, 0.3)');
gradient_stroke_green.addColorStop(0.5, 'rgba(75, 192, 192, 0.2)');
gradient_stroke_green.addColorStop(0.25, 'rgba(75, 192, 192, 0)');
var compulsory_routine_scrore = [
{% for score in score_routine1_list %}
@ -269,9 +270,9 @@
{
label: 'Q1R1',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_1,
borderColor: 'rgb(255, 99, 132)',
pointBackgroundColor: 'rgb(255, 99, 132)',
backgroundColor: gradient_stroke_pink,
borderColor: border_color_pink,
pointBackgroundColor: border_color_pink,
fill: true,
data: compulsory_routine_scrore
},
@ -281,9 +282,9 @@
{
label: 'Q1R2',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_2,
borderColor: 'rgb(255, 159, 64)',
pointBackgroundColor: 'rgb(255, 159, 64)',
backgroundColor: gradient_stroke_orange,
borderColor: border_color_orange,
pointBackgroundColor: border_color_orange,
fill: true,
data: voluntary_routine_scrore
},
@ -293,9 +294,9 @@
{
label: 'Q2R1',
cubicInterpolationMode: 'monotone',
backgroundColor: gradient_stroke_3,
borderColor: 'rgb(54, 162, 235)',
pointBackgroundColor: 'rgb(54, 162, 235)',
backgroundColor: border_color_green,
borderColor: border_color_green,
pointBackgroundColor: border_color_green,
fill: true,
data: final_routine_scrore
},
@ -339,79 +340,140 @@
{% if routine_one_done_list or routine_two_done_list %}
var ctx = document.getElementById('chart_routine_done').getContext('2d');
var border_color_pink = 'rgb(255, 99, 132)';
var gradient_stroke_pink = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_pink.addColorStop(1, 'rgba(255, 99, 132, 0.4)');
gradient_stroke_pink.addColorStop(0.75, 'rgba(255, 99, 132, 0.3)');
gradient_stroke_pink.addColorStop(0.5, 'rgba(255, 99, 132, 0.2)');
gradient_stroke_pink.addColorStop(0.25, 'rgba(255, 99, 132, 0)');
var border_color_orange = 'rgb(255, 159, 64)';
var gradient_stroke_orange = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_orange.addColorStop(1, 'rgba(255, 159, 64, 0.4)');
gradient_stroke_orange.addColorStop(0.75, 'rgba(255, 159, 64, 0.3)');
gradient_stroke_orange.addColorStop(0.5, 'rgba(255, 159, 64, 0.2)');
gradient_stroke_orange.addColorStop(0.25, 'rgba(255, 159, 64, 0)');
var border_color_green = 'rgb(75, 192, 192)';
var gradient_stroke_green = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_green.addColorStop(1, 'rgba(75, 192, 192, 0.4)');
gradient_stroke_green.addColorStop(0.75, 'rgba(75, 192, 192, 0.3)');
gradient_stroke_green.addColorStop(0.5, 'rgba(75, 192, 192, 0.2)');
gradient_stroke_green.addColorStop(0.25, 'rgba(75, 192, 192, 0)');
var border_color_blue = 'rgb(54, 162, 235)';
var gradient_stroke_blue = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_blue.addColorStop(1, 'rgba(54, 162, 235, 0.4)');
gradient_stroke_blue.addColorStop(0.75, 'rgba(54, 162, 235, 0.3)');
gradient_stroke_blue.addColorStop(0.5, 'rgba(54, 162, 235, 0.2)');
gradient_stroke_blue.addColorStop(0.25, 'rgba(54, 162, 235, 0)');
var border_color_yellow = 'rgb(255, 205, 86)';
var gradient_stroke_yellow = ctx.createLinearGradient(0, 230, 0, 50);
gradient_stroke_yellow.addColorStop(1, 'rgba(255, 205, 86, 0.4)');
gradient_stroke_yellow.addColorStop(0.75, 'rgba(255, 205, 86, 0.3)');
gradient_stroke_yellow.addColorStop(0.5, 'rgba(255, 205, 86, 0.2)');
gradient_stroke_yellow.addColorStop(0.25, 'rgba(255, 205, 86, 0)');
{% if routine_one_done_list %}
var routine_one_try = [
var routine_one = [
{% for routine_done in routine_one_done_list %}
{
x: '{{ routine_done.date | date:"d-m-Y" }}',
y: '{{ routine_done.number_of_try }}'
y: {% widthratio routine_done.number_of_successes routine_done.number_of_try 100 %}
},
{% endfor %}
];
var routine_one_success = [
{% for routine_done in routine_one_done_list %}
{
x: '{{ routine_done.date | date:"d-m-Y" }}',
y: '{{ routine_done.number_of_successes }}'
},
{% endfor %}
];
// var routine_one_try = [
// {% for routine_done in routine_one_done_list %}
// {
// x: '{{ routine_done.date | date:"d-m-Y" }}',
// y: '{{ routine_done.number_of_try }}'
// },
// {% endfor %}
// ];
// var routine_one_success = [
// {% for routine_done in routine_one_done_list %}
// {
// x: '{{ routine_done.date | date:"d-m-Y" }}',
// y: '{{ routine_done.number_of_successes }}'
// },
// {% endfor %}
// ];
{% endif %}
{% if routine_two_done_list %}
var routine_two_done = [
var routine_two = [
{% for routine_done in routine_two_done_list %}
{
x: '{{ routine_done.date | date:"d-m-Y" }}',
y: '{{ routine_done.number_of_try }}'
y: {% widthratio routine_done.number_of_successes routine_done.number_of_try 100 %}
},
{% endfor %}
];
var routine_two_success = [
{% for routine_done in routine_two_done_list %}
{
x: '{{ routine_done.date | date:"d-m-Y" }}',
y: '{{ routine_done.number_of_successes }}'
},
{% endfor %}
];
// var routine_two_done = [
// {% for routine_done in routine_two_done_list %}
// {
// x: '{{ routine_done.date | date:"d-m-Y" }}',
// y: '{{ routine_done.number_of_try }}'
// },
// {% endfor %}
// ];
// var routine_two_success = [
// {% for routine_done in routine_two_done_list %}
// {
// x: '{{ routine_done.date | date:"d-m-Y" }}',
// y: '{{ routine_done.number_of_successes }}'
// },
// {% endfor %}
// ];
{% endif %}
var score_values = {
datasets: [
{% if routine_one_done_list %}
{
label: 'Q1R1 Try',
label: 'Q1R1',
cubicInterpolationMode: 'monotone',
borderColor: 'rgb(75, 192, 192)',
pointBackgroundColor: 'rgb(75, 192, 192)',
data: routine_one_try,
},
{
label: 'Q1R1 success',
cubicInterpolationMode: 'monotone',
borderColor: 'rgb(255, 159, 64)',
pointBackgroundColor: 'rgb(255, 159, 64)',
data: routine_one_success,
backgroundColor: gradient_stroke_pink,
borderColor: border_color_pink,
pointBackgroundColor: border_color_pink,
fill: true,
data: routine_one,
},
// {
// label: 'Q1R1 success',
// cubicInterpolationMode: 'monotone',
// backgroundColor: gradient_stroke_orange,
// borderColor: border_color_orange,
// pointBackgroundColor: border_color_orange,
// fill: true,
// data: routine_one_success,
// },
{% endif %}
{% if routine_two_done_list %}
{
label: 'Q1R2 Try',
label: 'Q1R2',
cubicInterpolationMode: 'monotone',
borderColor: 'rgb(255, 99, 132)',
pointBackgroundColor: 'rgb(255, 99, 132)',
data: routine_two_done,
},
{
label: 'Q1R2 Success',
cubicInterpolationMode: 'monotone',
borderColor: 'rgb(54, 162, 235)',
pointBackgroundColor: 'rgb(54, 162, 235)',
data: routine_two_success,
backgroundColor: gradient_stroke_green,
borderColor: border_color_green,
pointBackgroundColor: border_color_green,
fill: true,
data: routine_two,
},
// {
// label: 'Q1R2 Success',
// cubicInterpolationMode: 'monotone',
// backgroundColor: gradient_stroke_blue,
// borderColor: border_color_blue,
// pointBackgroundColor: border_color_blue,
// fill: true,
// data: routine_two_success,
// },
{% endif %}
],
}

View File

@ -0,0 +1,119 @@
{% load has_group %}
<div class="row justify-content-center">
<div class="col-md-12 pl-0">
<div class="card mb-4">
<div class="card-header">
<div class="row">
<div class="col-8">
<h4>Season Informations</h4>
</div>
{% if request.user|has_group:"trainer" %}
<div class="col-1 ml-auto">
<div class="text-right">
<h3 class="mb-0">
<a href="{% url 'season_information_create_for_gymnast' gymnast.id %}">
<i class="fas fa-plus text-warning"></i>
</a>
</h3>
</div>
</div>
{% endif %}
</div>
</div>
<div class="card-body">
{% if season_information_list %}
<table class="table tablesorter table-striped mb-0" data-sort="table" id="season_informations_table">
<thead>
<tr>
<th></th>
<th class="header text-center">Season</th>
<th class="header text-center"># training/w</th>
<th class="header text-center"># hours/w</th>
<th class="header text-center"># S&C/w</th>
<th class="header text-center"># S&C hours/w</th>
<th class="header text-center">category</th>
</tr>
</thead>
<tbody>
{% for season_information in season_information_list %}
<tr>
<td>
<a href="{% url 'season_information_update' season_information.id %}">
<span class="tim-icons icon-pencil text-warning"></span>
</a>
</td>
<td class="text-center"><a href="{% url 'season_information_details' season_information.id %}">{{ season_information.season }}</a></td>
<td class="text-center">{{ season_information.number_of_training_sessions_per_week }}</td>
<td class="text-center"><b>{{ season_information.number_of_hours_per_week }}</b></td>
<td class="text-center">{{ season_information.number_of_s_and_c_sessions_per_week }}</td>
<td class="text-center"><b>{{ season_information.number_of_s_and_c_hours_per_week }}</b></td>
<td class="text-center"><b>{{ season_information.category.short_label }}</b></td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
There are no scores corresponding to your criterias
{% endif %}
</div>
</div>
</div>
<div class="col-md-4 pl-0">
<div class="card mb-4">
<div class="card-header">
<div class="row">
<div class="col-8">
<h4>Trainers</h4>
</div>
<div class="col-2 ml-auto">
<div class="text-right">
<h4 class="mb-0">
<a href="{% url 'gymnast_trainers_listing' gymnast.id %}">
<span class="tim-icons icon-pencil text-warning"></span>
</a>
</h4>
</div>
</div>
</div>
</div>
<div class="card-body pt-0">
{% if trainers_list %}
<table class="table table-striped table-condensed mb-0" id="trainers_table">
<tbody>
{% for trainer in trainers_list %}
<tr>
<td class="text-center">{{ trainer.first_name }} {{ trainer.last_name }}{% if trainer.is_superuser %} <span class="text-muted">(Admin)</span>{% endif %}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>Nobody can see your profile.</p>
{% endif %}
</div>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function () {
$('[data-sort="table"]').tablesorter({
headers: {
0: { sorter: false },
},
dateFormat : "ddmmyyyy",
sortList: [[1, 1]]
});
$('#score_table').DataTable({
scrollY: '50vh',
scrollCollapse: true,
paging: false,
searching: false,
ordering: false,
// "bInfo" : false,
});
});
</script>

View File

@ -1,9 +1,9 @@
{% load has_group %}
<div class="row justify-content-center ml-1">
<div class="col-md-12">
<div class="row justify-content-center">
<div class="col-md-12 pl-0">
<div class="card">
<div class="card-body">
<div class="card-body" style="height=50vh;">
{% if planned_skill or skill_whith_help or skill_without_help or skill_chained or skill_masterised or skill_by_rank or skill_by_level or skill_by_age or unknown_skill %}
<ul class="nav nav-pills nav-pills-warning nav-pills-icons justify-content-center">
{% if planned_skill %}
@ -87,10 +87,10 @@
{% endif %}
</ul>
<div class="tab-content tab-space tab-subcategories pt-0 pb-0">
<div class="tab-content tab-space tab-subcategories p-0">
{% if planned_skill %}
<div class="tab-pane {% if planned_skill %}active{% endif %}" id="planned_skill">
<table class="table table-condensed table-striped tablesorter" id="table_planned_skill">
<table class="table table-condensed table-striped tablesorter m-0 p-0" id="table_planned_skill">
<thead>
<tr>
<th style="width: 15%"></th>
@ -98,9 +98,9 @@
<th class="header text-left" style="width: 35%">Label</th>
<th class="header text-left" style="width: 10%">Phase</th>
<th class="header text-left" style="width: 10%">Deadline</th>
<th class="header" style="width: 7%">Diff.</th>
<th class="header" style="width: 8%">Level</th>
<th class="header" style="width: 13%">Rank</th>
<th class="header not-displayed-on-phone" style="width: 7%">Diff.</th>
<th class="header not-displayed-on-phone" style="width: 8%">Level</th>
<th class="header not-displayed-on-phone" style="width: 13%">Rank</th>
</tr>
</thead>
<tbody>
@ -138,9 +138,9 @@
{{ plan.date | date:"d-m-Y" }}
{% if plan.is_past %}</b></span>{% endif %}
</td>
<td>{{ plan.educative.difficulty }}</td>
<td>{{ plan.educative.level }}</td>
<td>{{ plan.educative.rank }}</td>
<td class="not-displayed-on-phone">{{ plan.educative.difficulty }}</td>
<td class="not-displayed-on-phone">{{ plan.educative.level }}</td>
<td class="not-displayed-on-phone">{{ plan.educative.rank }}</td>
</tr>
{% endfor %}
</tbody>
@ -150,15 +150,15 @@
{% if confused_skill %}
<div class="tab-pane {% if confused_skill and not planned_skill %}active{% endif %}" id="confused_skill">
<table class="table table-striped table-condensed tablesorter" id="table_confused_skill">
<table class="table table-striped table-condensed tablesorter m-0 p-0" id="table_confused_skill">
<thead>
<tr>
<th style="width: 10%"></th>
<th style="width: 10%">Notation</th>
<th class="header text-left" style="width: 35%">Label</th>
<th class="header" style="width: 7%">Diff.</th>
<th class="header" style="width: 7%">Level</th>
<th class="header" style="width: 7%">Rank</th>
<th class="header not-displayed-on-phone" style="width: 7%">Diff.</th>
<th class="header not-displayed-on-phone" style="width: 7%">Level</th>
<th class="header not-displayed-on-phone" style="width: 7%">Rank</th>
</tr>
</thead>
<tbody>
@ -184,9 +184,9 @@
<td class="text-left">
<a href="{% url 'skill_details' skill.id %}">{{ skill.long_label }}</a>
</td>
<td>{{ skill.difficulty }}</td>
<td>{{ skill.level }}</td>
<td>{{ skill.rank }}</td>
<td class="not-displayed-on-phone">{{ skill.difficulty }}</td>
<td class="not-displayed-on-phone">{{ skill.level }}</td>
<td class="not-displayed-on-phone">{{ skill.rank }}</td>
</tr>
{% endfor %}
</tbody>
@ -196,15 +196,15 @@
{% if skill_whith_help %}
<div class="tab-pane {% if skill_whith_help and not confused_skill and not planned_skill %}active{% endif %}" id="skill_whith_help">
<table class="table table-striped table-condensed tablesorter" id="table_skill_with_help">
<table class="table table-striped table-condensed tablesorter m-0 p-0" id="table_skill_with_help">
<thead>
<tr>
<th style="width: 10%"></th>
<th style="width: 10%">Notation</th>
<th class="header text-left" style="width: 35%">Label</th>
<th class="header" style="width: 7%">Diff.</th>
<th class="header" style="width: 7%">Level</th>
<th class="header" style="width: 7%">Rank</th>
<th class="header not-displayed-on-phone" style="width: 7%">Diff.</th>
<th class="header not-displayed-on-phone" style="width: 7%">Level</th>
<th class="header not-displayed-on-phone" style="width: 7%">Rank</th>
</tr>
</thead>
<tbody>
@ -228,9 +228,9 @@
<td>{{ skill.notation }}</td>
<td class="text-left"><a href="{% url 'skill_details' skill.id %}">{{ skill.long_label }}</a></td>
<td>{{ skill.difficulty }}</td>
<td>{{ skill.level }}</td>
<td>{{ skill.rank }}</td>
<td class="not-displayed-on-phone">{{ skill.difficulty }}</td>
<td class="not-displayed-on-phone">{{ skill.level }}</td>
<td class="not-displayed-on-phone">{{ skill.rank }}</td>
</tr>
{% endfor %}
</tbody>
@ -240,15 +240,15 @@
{% if skill_without_help %}
<div class="tab-pane {% if skill_without_help and not skill_whith_help and not confused_skill and not planned_skill %}active{% endif %}" id="skill_without_help">
<table class="table table-striped table-condensed tablesorter" id="table_skill_without_help">
<table class="table table-striped table-condensed tablesorter m-0 p-0" id="table_skill_without_help">
<thead>
<tr>
<th style="width: 12%"></th>
<th style="width: 10%">Notation</th>
<th class="header text-left" style="width: 55%">Label</th>
<th class="header" style="width: 7%">Diff.</th>
<th class="header" style="width: 7%">Level</th>
<th class="header" style="width: 7%">Rank</th>
<th class="header not-displayed-on-phone" style="width: 7%">Diff.</th>
<th class="header not-displayed-on-phone" style="width: 7%">Level</th>
<th class="header not-displayed-on-phone" style="width: 7%">Rank</th>
</tr>
</thead>
<tbody>
@ -272,9 +272,9 @@
<td>{{ skill.notation }}</td>
<td class="text-left"><a href="{% url 'skill_details' skill.id %}">{{ skill.long_label }}</a></td>
<td>{{ skill.difficulty }}</td>
<td>{{ skill.level }}</td>
<td>{{ skill.rank }}</td>
<td class="not-displayed-on-phone">{{ skill.difficulty }}</td>
<td class="not-displayed-on-phone">{{ skill.level }}</td>
<td class="not-displayed-on-phone">{{ skill.rank }}</td>
</tr>
{% endfor %}
</tbody>
@ -284,15 +284,15 @@
{% if skill_chained %}
<div class="tab-pane {% if skill_chained and not skill_without_help and not skill_whith_help and not confused_skill and not planned_skill %}active{% endif %}" id="skill_chained">
<table class="table table-striped table-condensed tablesorter" id="table_skill_chained">
<table class="table table-striped table-condensed tablesorter m-0 p-0" id="table_skill_chained">
<thead>
<tr>
<th style="width: 12%"></th>
<th style="width: 10%">Notation</th>
<th class="header text-left" style="width: 35%">Label</th>
<th class="header" style="width: 7%">Diff.</th>
<th class="header" style="width: 7%">Level</th>
<th class="header" style="width: 7%">Rank</th>
<th class="header not-displayed-on-phone" style="width: 7%">Diff.</th>
<th class="header not-displayed-on-phone" style="width: 7%">Level</th>
<th class="header not-displayed-on-phone" style="width: 7%">Rank</th>
</tr>
</thead>
<tbody>
@ -316,9 +316,9 @@
<td>{{ skill.notation }}</td>
<td class="text-left"><a href="{% url 'skill_details' skill.id %}">{{ skill.long_label }}</a></td>
<td>{{ skill.difficulty }}</td>
<td>{{ skill.level }}</td>
<td>{{ skill.rank }}</td>
<td class="not-displayed-on-phone">{{ skill.difficulty }}</td>
<td class="not-displayed-on-phone">{{ skill.level }}</td>
<td class="not-displayed-on-phone">{{ skill.rank }}</td>
</tr>
{% endfor %}
</tbody>
@ -328,28 +328,28 @@
{% if skill_masterised %}
<div class="tab-pane {% if skill_masterised and not skill_chained and not skill_without_help and not skill_whith_help and not confused_skill and not planned_skill %}active{% endif %}" id="skill_masterised">
<table class="table table-striped table-condensed tablesorter" id="table_skill_masterised">
<table class="table table-striped table-condensed tablesorter m-0 p-0" id="table_skill_masterised">
<thead>
<tr>
<th style="width: 12%"></th>
<th style="width: 10%">Notation</th>
<th class="header text-left" style="width: 35%">Label</th>
<th class="header" style="width: 7%">Diff.</th>
<th class="header" style="width: 7%">Level</th>
<th class="header" style="width: 7%">Rank</th>
<th class="header not-displayed-on-phone" style="width: 7%">Diff.</th>
<th class="header not-displayed-on-phone" style="width: 7%">Level</th>
<th class="header not-displayed-on-phone" style="width: 7%">Rank</th>
</tr>
</thead>
<tbody>
{% for skill in skill_masterised %}
<tr>
<td>
<button type="button" rel="tooltip" class="btn btn-success btn-link btn-sm btn-icon checkUnknownSkill text-with-help" data-gymnast_id="{{ gymnast.id }}" data-skill_id="{{ plan.educative.id }}" data-learning_step="1">
<button type="button" rel="tooltip" class="btn btn-success btn-link btn-sm btn-icon checkUnknownSkill text-with-help" data-gymnast_id="{{ gymnast.id }}" data-skill_id="{{ skill.id }}" data-learning_step="1">
<i class="far fa-check"></i>
</button>
<button type="button" rel="tooltip" class="btn btn-success btn-link btn-sm btn-icon checkUnknownSkill text-without-help" data-gymnast_id="{{ gymnast.id }}" data-skill_id="{{ plan.educative.id }}" data-learning_step="2">
<button type="button" rel="tooltip" class="btn btn-success btn-link btn-sm btn-icon checkUnknownSkill text-without-help" data-gymnast_id="{{ gymnast.id }}" data-skill_id="{{ skill.id }}" data-learning_step="2">
<i class="far fa-check-double"></i>
</button>
<button type="button" rel="tooltip" class="btn btn-success btn-link btn-sm btn-icon checkUnknownSkill text-chained" data-gymnast_id="{{ gymnast.id }}" data-skill_id="{{ plan.educative.id }}" data-learning_step="3">
<button type="button" rel="tooltip" class="btn btn-success btn-link btn-sm btn-icon checkUnknownSkill text-chained" data-gymnast_id="{{ gymnast.id }}" data-skill_id="{{ skill.id }}" data-learning_step="3">
<i class="far fa-link"></i>
</button>
<!-- MASTERISED -->
@ -360,9 +360,9 @@
<td>{{ skill.notation }}</td>
<td class="text-left"><a href="{% url 'skill_details' skill.id %}">{{ skill.long_label }}</a></td>
<td>{{ skill.difficulty }}</td>
<td>{{ skill.level }}</td>
<td>{{ skill.rank }}</td>
<td class="not-displayed-on-phone">{{ skill.difficulty }}</td>
<td class="not-displayed-on-phone">{{ skill.level }}</td>
<td class="not-displayed-on-phone">{{ skill.rank }}</td>
</tr>
{% endfor %}
</tbody>
@ -372,15 +372,15 @@
{% if skill_by_rank %}
<div class="tab-pane {% if skill_by_rank and not skill_masterised and not skill_chained and not skill_without_help and not skill_whith_help and not confused_skill and not planned_skill %}active{% endif %}" id="skill_by_rank">
<table class="table table-striped table-condensed tablesorter" id="table_by_rank">
<table class="table table-striped table-condensed tablesorter m-0 p-0" id="table_by_rank">
<thead>
<tr>
<th style="width: 13%">Actions</th>
<th style="width: 10%">Notation</th>
<th class="header text-left" style="width: 50%">Label</th>
<th class="header" style="width: 7%">Diff.</th>
<th class="header" style="width: 7%">Level</th>
<th class="header" style="width: 7%">Rank</th>
<th class="header not-displayed-on-phone" style="width: 7%">Diff.</th>
<th class="header not-displayed-on-phone" style="width: 7%">Level</th>
<th class="header not-displayed-on-phone" style="width: 7%">Rank</th>
</tr>
</thead>
<tbody>
@ -408,9 +408,9 @@
<td>{{ skill.notation }}</td>
<td class="text-left"><a href="{% url 'skill_details' skill.id %}">{{ skill.long_label }}</a></td>
<td>{{ skill.difficulty }}</td>
<td>{{ skill.level }}</td>
<td>{{ skill.rank }}</td>
<td class="not-displayed-on-phone">{{ skill.difficulty }}</td>
<td class="not-displayed-on-phone">{{ skill.level }}</td>
<td class="not-displayed-on-phone">{{ skill.rank }}</td>
</tr>
{% endfor %}
</tbody>
@ -420,15 +420,15 @@
{% if skill_by_level %}
<div class="tab-pane {% if skill_by_level and not skill_by_rank and not skill_masterised and not skill_chained and not skill_without_help and not skill_whith_help and not confused_skill and not planned_skill %}active{% endif %}" id="skill_by_level">
<table class="table table-striped table-condensed tablesorter" id="table_by_level">
<table class="table table-striped table-condensed tablesorter m-0 p-0" id="table_by_level">
<thead>
<tr>
<th style="width: 15%">Actions</th>
<th style="width: 10%">Notation</th>
<th class="header text-left" style="width: 50%">Label</th>
<th class="header" style="width: 7%">Diff.</th>
<th class="header" style="width: 7%">Level</th>
<th class="header" style="width: 7%">Rank</th>
<th class="header not-displayed-on-phone" style="width: 7%">Diff.</th>
<th class="header not-displayed-on-phone" style="width: 7%">Level</th>
<th class="header not-displayed-on-phone" style="width: 7%">Rank</th>
</tr>
</thead>
<tbody>
@ -456,9 +456,9 @@
<td>{{ skill.notation }}</td>
<td class="text-left"><a href="{% url 'skill_details' skill.id %}">{{ skill.long_label }}</a></td>
<td>{{ skill.difficulty }}</td>
<td>{{ skill.level }}</td>
<td>{{ skill.rank }}</td>
<td class="not-displayed-on-phone">{{ skill.difficulty }}</td>
<td class="not-displayed-on-phone">{{ skill.level }}</td>
<td class="not-displayed-on-phone">{{ skill.rank }}</td>
</tr>
{% endfor %}
</tbody>
@ -468,15 +468,15 @@
{% if skill_by_age %}
<div class="tab-pane {% if skill_by_age and not skill_by_level and not skill_by_rank and not skill_masterised and not skill_chained and not skill_without_help and not skill_whith_help and not confused_skill and not planned_skill %}active{% endif %}" id="skill_by_age">
<table class="table table-striped table-condensed tablesorter" id="table_by_age">
<table class="table table-striped table-condensed tablesorter m-0 p-0" id="table_by_age">
<thead>
<tr>
<th style="width: 15%">Actions</th>
<th style="width: 10%">Notation</th>
<th class="header text-left" style="width: 50%">Label</th>
<th class="header" style="width: 7%">Diff.</th>
<th class="header" style="width: 7%">Level</th>
<th class="header" style="width: 7%">Rank</th>
<th class="header not-displayed-on-phone" style="width: 7%">Diff.</th>
<th class="header not-displayed-on-phone" style="width: 7%">Level</th>
<th class="header not-displayed-on-phone" style="width: 7%">Rank</th>
</tr>
</thead>
@ -505,9 +505,9 @@
<td>{{ skill.notation }}</td>
<td class="text-left"><a href="{% url 'skill_details' skill.id %}">{{ skill.long_label }}</a></td>
<td>{{ skill.difficulty }}</td>
<td>{{ skill.level }}</td>
<td>{{ skill.rank }}</td>
<td class="not-displayed-on-phone">{{ skill.difficulty }}</td>
<td class="not-displayed-on-phone">{{ skill.level }}</td>
<td class="not-displayed-on-phone">{{ skill.rank }}</td>
</tr>
{% endfor %}
</tbody>
@ -517,15 +517,15 @@
{% if unknown_skill %}
<div class="tab-pane {% if unknown_skill and not skill_by_age and not skill_by_level and not skill_by_rank and not skill_masterised and not skill_chained and not skill_without_help and not skill_whith_help and not confused_skill and not planned_skill %}active{% endif %}" id="unknown_skill">
<table class="table table-striped table-condensed tablesorter" id="table_unknown_skill">
<table class="table tablesorter table-striped m-0 p-0" data-sort="table" id="table_unknown_skill" style="width: 100%">
<thead>
<tr>
<th style="width: 15%">Actions</th>
<th style="width: 10%">Notation</th>
<th class="header text-left" style="width: 50%">Label</th>
<th class="header" style="width: 7%">Diff.</th>
<th class="header" style="width: 7%">Level</th>
<th class="header" style="width: 7%">Rank</th>
<th class="header">Actions</th>
<th class="header">Notation</th>
<th class="header text-left">Label</th>
<th class="header not-displayed-on-phone">Diff.</th>
<th class="header not-displayed-on-phone">Level</th>
<th class="header not-displayed-on-phone">Rank</th>
</tr>
</thead>
<tbody>
@ -553,9 +553,9 @@
<td>{{ skill.notation }}</td>
<td class="text-left"><a href="{% url 'skill_details' skill.id %}">{{ skill.long_label }}</a></td>
<td>{{ skill.difficulty }}</td>
<td>{{ skill.level }}</td>
<td>{{ skill.rank }}</td>
<td class="not-displayed-on-phone">{{ skill.difficulty }}</td>
<td class="not-displayed-on-phone">{{ skill.level }}</td>
<td class="not-displayed-on-phone">{{ skill.rank }}</td>
</tr>
{% endfor %}
</tbody>
@ -579,7 +579,7 @@
$('.checkUnknownSkill').click(function(){
$.ajax({
// TODO: chande hardcoded url
url: '/follow-up/learnedskill/new/',
url: '{% url "gymnast_learn_skill" %}',
data: {
gymnast_id: $(this).data('gymnast_id'),
skill_id: $(this).data('skill_id'),
@ -589,8 +589,7 @@
type: 'POST',
context: $(this),
success: function (response) {
// avec reload (data à jour)
// location.reload();
// location.reload(); // avec reload (data à jour)
// sans relaod des datas (data pas totalement à jour)
$(this).closest('tr').fadeTo("slow", 0.0, function(){
@ -613,7 +612,6 @@
0: { sorter: false }, // disable first column
},
{% endif %}
// dateFormat: "uk",
sortList: [[5,0], [4,0], [2,0]]
});
@ -623,8 +621,19 @@
0: { sorter: false }, // disable first column
},
{% endif %}
// dateFormat: "uk",
sortList: [[3, 0], [6,0], [5,0], [3, 0]]
});
// $('#table_by_rank, #table_by_level, #table_by_age, #table_unknown_skill, #table_skill_with_help, #table_skill_without_help, #table_skill_chained').DataTable({
// scrollY: '65vh',
// });
// $('#table_skill_chained').DataTable({
// searching: false,
// // scrollY: '60vh',
// ordering: false,
// paging: false,
// info: false,
// });
});
</script>

View File

@ -47,7 +47,15 @@ gymnast_urlpatterns = [
views_reports.report_choice,
name="gymnast_report_list",
),
path(
r"details/<int:gymnast_id>/season_informations/",
views.gymnast_display_season_informations,
name="gymnast_display_season_informations",
),
path(r"add/", views.gymnast_create_or_update, name="gymnast_create"),
path(r"<int:gymnast_id>/trainer/", views.gymnast_trainers_listing, name="gymnast_trainers_listing"),
path(r"<int:gymnast_id>/add/trainer/", views.link_trainer_to_gymnast, name="link_trainer_to_gymnast"),
path(r"<int:gymnast_id>/remove/trainer/", views.unlink_trainer_to_gymnast, name="unlink_trainer_to_gymnast"),
path(
r"edit/<int:gymnast_id>/", views.gymnast_create_or_update, name="gymnast_update"
),

View File

@ -8,7 +8,7 @@ from django.db.models import (
Q,
Avg,
)
from django.http import HttpResponseRedirect, JsonResponse
from django.http import HttpResponseRedirect, JsonResponse, HttpResponse
from django.shortcuts import render, get_object_or_404
from django.views.decorators.http import require_http_methods
from django.urls import reverse
@ -20,7 +20,6 @@ import pendulum
from jarvis.followup.models import Event
from jarvis.followup.forms import GymnastHasRoutineForm
from jarvis.objective.models import TrainingProgram
from jarvis.followup.models import (
Note,
Plan,
@ -43,7 +42,6 @@ from .forms import GymnastForm, UserForm
User = get_user_model()
@login_required
@require_http_methods(["POST"])
def gymnast_lookup(request):
@ -58,10 +56,6 @@ def gymnast_lookup(request):
if pattern is not None and len(pattern) > 2:
name = clean_name(pattern)
# gymnast_list = Gymnast.objects.filter(
# Q(cleaned_last_name__icontains=name) | Q(cleaned_first_name__icontains=name)
# )
gymnast_list = Gymnast.objects.filter(
is_active=True, pk__in=request.session["available_gymnast"]
).filter(
@ -83,7 +77,7 @@ def gymnast_listing(request):
"""
season = Season()
if request.user.groups.filter(name="trainer").exists():
if request.user.is_superuser or request.user.groups.filter(name="trainer").exists():
season_information_list = SeasonInformation.objects.filter(
season=season.label
).select_related("gymnast")
@ -107,6 +101,9 @@ def gymnast_details(request, gymnast_id, tab=None):
"""
if request.user.is_superuser or (
hasattr(request.user, 'gymnast')
and request.user.gymnast.id == gymnast_id
) or (
request.session.has_key("available_gymnast")
and gymnast_id in request.session["available_gymnast"]
):
@ -161,12 +158,31 @@ def gymnast_details(request, gymnast_id, tab=None):
"percentage_known_skill": percentage_known_skill,
"tab": tab,
}
context["user_is_trainer"] = request.user.groups.filter(
name="trainer"
).exists() # TODO: utiliser les {{ perms }}
#TODO: utiliser les {{ perms }}
context["user_is_trainer"] = request.user.groups.filter(name="trainer").exists()
return render(request, "gymnasts/details.html", context)
@login_required
@require_http_methods(["GET"])
def gymnast_display_season_informations(request, gymnast_id):
"""
Renvoie la liste des seasons informations pour un gymnast.
Args:
gymnast_id (int) identifiant du gymnast
"""
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
trainers_list = gymnast.trainers.all().order_by("first_name", "last_name")
season_information_list = gymnast.season_informations.all()
context = {
"gymnast": gymnast,
"trainers_list": trainers_list,
"season_information_list": season_information_list,
}
return render(request, "gymnasts/tabs/tab_season_informations.html", context)
@login_required
@require_http_methods(["GET"])
def gymnast_display_events_and_notes(request, gymnast_id):
@ -201,7 +217,7 @@ def gymnast_display_events_and_notes(request, gymnast_id):
"latest_published_note": latest_published_note,
"gymnast_id": gymnast_id,
}
return render(request, "gymnasts/tabs/tab_events_and_notes.html", context)
return render(request, "gymnasts/tabs/tab_notes_events.html", context)
@login_required
@ -214,8 +230,8 @@ def gymnast_display_physiological(request, gymnast_id):
gymnast_id (int) identifiant du gymnast
"""
number_of_injuries = Injury.objects.filter(gymnast=gymnast_id).count()
start_date = pendulum.now().date().subtract(months=6)
injuries_list = Injury.objects.filter(
start_date = pendulum.now().date().subtract(months=2)
injury_list = Injury.objects.filter(
gymnast=gymnast_id, date__gte=start_date
).order_by("date")
wellbeing_list = WellBeing.objects.filter(
@ -223,17 +239,20 @@ def gymnast_display_physiological(request, gymnast_id):
).order_by("date")
height_weight_list = HeightWeight.objects.filter(
gymnast=gymnast_id, date__gte=start_date
).order_by("date")
)
if height_weight_list.count() <= 3:
height_weight_list = HeightWeight.objects.filter(gymnast=gymnast_id).order_by("-date")[:5][::-1]
context = {
"injuries_list": injuries_list,
"injury_list": injury_list,
"number_of_injuries": number_of_injuries,
"wellbeing_list": wellbeing_list,
"height_weight_list": height_weight_list,
"gymnast_id": gymnast_id,
}
return render(
request, "gymnasts/tabs/tab_physiological_and_wellbeing.html", context
request, "gymnasts/tabs/tab_height_weight_wellbeing_injury.html", context
)
@ -256,13 +275,6 @@ def gymnast_display_scores_chrono(request, gymnast_id):
gymnast=gymnast_id, date__gte=start_date
).order_by("date")
base_queryset = chrono_list.values("date").annotate(score_avg=Avg("tof"))
today = pendulum.now().date()
date_list = (
TrainingProgram.objects.filter(gymnast=gymnast_id, date__gte=today)
.values_list("date", flat=True)
.order_by("date")
.distinct()
)
context = {
"intensity_list": intensity_list,
@ -271,10 +283,9 @@ def gymnast_display_scores_chrono(request, gymnast_id):
"chrono_r1": base_queryset.filter(chrono_type=1),
"chrono_r2": base_queryset.filter(chrono_type=2),
"chrono_rf": base_queryset.filter(chrono_type=3),
"date_list": date_list,
"gymnast_id": gymnast_id,
}
return render(request, "gymnasts/tabs/tab_intensity_and_chronos.html", context)
return render(request, "gymnasts/tabs/tab_intensity_chronos_programs.html", context)
@login_required
@ -320,7 +331,7 @@ def gymnast_display_routine_statistics(request, gymnast_id):
"score_routine3_list": score_list.filter(routine_type=3),
"gymnast_id": gymnast_id,
}
return render(request, "gymnasts/tabs/tab_routines_and_scores.html", context)
return render(request, "gymnasts/tabs/tab_routines_scores.html", context)
@login_required
@ -430,13 +441,65 @@ def gymnast_create_or_update(request, gymnast_id=None):
return HttpResponseRedirect(reverse("gymnast_details", args=(gymnast.pk,)))
return render(request, "people/gymnasts/create.html", {"form": gymnast_form})
return render(request, "gymnasts/create.html", {"form": gymnast_form})
form = GymnastForm(instance=gymnast)
context = {"form": form, "gymnast_id": gymnast_id}
return render(request, "gymnasts/create.html", context)
@login_required
@require_http_methods(["GET", "POST"])
def gymnast_trainers_listing(request, gymnast_id):
""" Liste tous les user """
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
user_list = User.objects.filter(is_active=True, groups__name="trainer").order_by('first_name', 'last_name')
rows = gymnast.trainers.values("id")
already_linked = [row["id"] for row in rows]
context = {
"gymnast": gymnast,
"already_linked": already_linked,
"trainers_list": user_list,
}
return render(request, "gymnasts/link_trainer_to_gymnast.html", context)
@login_required
@require_http_methods(["POST"])
def link_trainer_to_gymnast(request, gymnast_id):
""" Lie un entraîneur à un gymnaste. """
trainer_id = request.POST.get("trainer_id", None)
if gymnast_id and trainer_id:
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
gymnast.trainers.add(get_object_or_404(User, pk=trainer_id))
return HttpResponse(status=200)
if gymnast_id:
print("Error : can not link Gymnast and Trainer. Missing trainer id.")
else:
print("Error : can not link Gymnast and Trainer. Missing gymnast id.")
return HttpResponse(status=500)
@login_required
@require_http_methods(["POST"])
def unlink_trainer_to_gymnast(request, gymnast_id):
""" Délie un entraîneur d'un gymanste. """
trainer_id = request.POST.get("trainer_id", None)
if gymnast_id and trainer_id:
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
gymnast.trainers.remove(get_object_or_404(User, pk=trainer_id))
return HttpResponse(status=200)
if gymnast_id:
print("Error : can not link Gymnast and Trainer. Missing trainer id.")
else:
print("Error : can not link Gymnast and Trainer. Missing gymnast id.")
return HttpResponse(status=500)
@login_required
@require_http_methods(["GET"])
def gymnast_display_skill(request, gymnast_id):

View File

@ -22,21 +22,13 @@ from weasyprint import HTML, CSS
import pendulum
from jarvis.followup.models import Event
from jarvis.followup.models import (
Note,
Plan,
Skill,
Point,
Chrono,
Injury,
WellBeing,
Intensity,
LearnedSkill,
HeightWeight,
SeasonInformation,
NumberOfRoutineDone,
)
from jarvis.followup.models import LEARNING_STEP_CHOICES
@ -761,25 +753,25 @@ def generate_report_for_period(
"notes": notes,
}
return render(request, "gymnasts/reports/report_periodical.html", context)
# return render(request, "gymnasts/reports/report_periodical.html", context)
# response = HttpResponse(content_type="application/pdf")
# response[
# "Content-Disposition"
# ] = f"attachment; filename={gymnast.last_name}_{gymnast.first_name}_{period}-report_{date_begin}_{date_end}.pdf" # pylint: disable=line-too-long
response = HttpResponse(content_type="application/pdf")
response[
"Content-Disposition"
] = f"attachment; filename={gymnast.last_name}_{gymnast.first_name}_{period}-report_{date_begin}_{date_end}.pdf" # pylint: disable=line-too-long
# html = render_to_string("gymnasts/reports/report_periodical.html", context)
html = render_to_string("gymnasts/reports/report_periodical.html", context)
# # font_config = FontConfiguration()
# HTML(string=html, base_url=request.build_absolute_uri()).write_pdf(
# response,
# stylesheets=[
# CSS(settings.STATICFILES_DIRS[0] + "/css/gymnast_report.css"),
# CSS(settings.STATICFILES_DIRS[0] + "/css/black-dashboard_report.css"),
# CSS(settings.STATICFILES_DIRS[0] + "/css/font_awesome_all_5.15.3.css"),
# ],
# ) # , font_config=font_config)
# return response
# font_config = FontConfiguration()
HTML(string=html, base_url=request.build_absolute_uri()).write_pdf(
response,
stylesheets=[
CSS(settings.STATICFILES_DIRS[0] + "/css/a4_paper.css"),
CSS(settings.STATICFILES_DIRS[0] + "/css/black-dashboard_report.css"),
CSS(settings.STATICFILES_DIRS[0] + "/css/font_awesome_all_5.15.3.css"),
],
) # , font_config=font_config)
return response
@login_required
@ -910,7 +902,7 @@ def generate_report_week_comparison(
# HTML(string=html, base_url=request.build_absolute_uri()).write_pdf(
# response,
# stylesheets=[
# CSS(settings.STATICFILES_DIRS[0] + "/css/gymnast_report.css"),
# CSS(settings.STATICFILES_DIRS[0] + "/css/a4_paper.css"),
# CSS(settings.STATICFILES_DIRS[0] + "/css/black-dashboard_report.css"),
# CSS(settings.STATICFILES_DIRS[0] + "/css/font_awesome_all_5.15.3.css"),
# ],
@ -1110,7 +1102,7 @@ def generate_timeline_report(
HTML(string=html, base_url=request.build_absolute_uri()).write_pdf(
response,
stylesheets=[
CSS(settings.STATICFILES_DIRS[0] + "/css/gymnast_report.css"),
CSS(settings.STATICFILES_DIRS[0] + "/css/a4_paper.css"),
CSS(settings.STATICFILES_DIRS[0] + "/css/black-dashboard_report.css"),
CSS(settings.STATICFILES_DIRS[0] + "/css/font_awesome_all_5.15.3.css"),
],

Some files were not shown because too many files have changed in this diff Show More