Refactor code

This commit is contained in:
PhilippHofer 2023-09-05 20:48:02 +00:00
parent 709411ce5c
commit a1dc92defd
No known key found for this signature in database
13 changed files with 346 additions and 310 deletions

33
frontend/logbook.ts Normal file
View File

@ -0,0 +1,33 @@
/*document.addEventListener('DOMContentLoaded', function() {
setDistance('.set-distance-js');
});
function setDistance(selector: string) {
const fields = document.querySelectorAll(selector);
if(fields) {
Array.prototype.forEach.call(fields, (field: HTMLInputElement) => {
if(field.dataset.relation){
const relatedField = <HTMLInputElement>document.getElementById(field.dataset.relation);
if(relatedField) {
field.addEventListener('input', (e) => {
e.preventDefault();
const dataList = <HTMLDataListElement>document.getElementById('destinations');
if(dataList) {
var option = Array.prototype.find.call(dataList.options, function(option) {
return option.value === field.value;
});
// Get distance
const distance = option.getAttribute('distance');
if(distance) relatedField.value = distance;
}
});
}
}
});
}
}
*/
export {}

View File

@ -202,9 +202,22 @@ function initTripSidebar(triggerElement: HTMLElement) {
} }
}); });
const prefixedContent = <NodeListOf<HTMLElement>>bodyElement.querySelectorAll('.change-id-js');
Array.prototype.forEach.call(prefixedContent, (content: HTMLElement) => {
if(content) {
content.id += 'js';
if(content.dataset.relation){
content.dataset.relation += 'js';
}
}
});
if(bodyContainerElement) { if(bodyContainerElement) {
bodyContainerElement.innerHTML = ''; bodyContainerElement.innerHTML = '';
bodyContainerElement.append(bodyElement); bodyContainerElement.append(bodyElement);
addRelationMagic(bodyElement);
} }
if(triggerElement.dataset.day) { if(triggerElement.dataset.day) {
let hiddenElement = <HTMLInputElement>bodyElement.querySelector('.day-js'); let hiddenElement = <HTMLInputElement>bodyElement.querySelector('.day-js');
@ -220,6 +233,33 @@ function initTripSidebar(triggerElement: HTMLElement) {
} }
} }
function addRelationMagic(bodyElement: HTMLElement) {
const fields = bodyElement.querySelectorAll('.set-distance-js');
if(fields) {
Array.prototype.forEach.call(fields, (field: HTMLInputElement) => {
if(field.dataset.relation){
const relatedField = <HTMLInputElement>bodyElement.querySelector('#' + field.dataset.relation);
if(relatedField) {
field.addEventListener('input', (e) => {
e.preventDefault();
const dataList = <HTMLDataListElement>document.getElementById('destinations');
if(dataList) {
var option = Array.prototype.find.call(dataList.options, function(option) {
return option.value === field.value;
});
// Get distance
const distance = option.getAttribute('distance');
if(distance) relatedField.value = distance;
}
});
}
}
});
}
}
function replaceStrings() { function replaceStrings() {
const weekdays = document.querySelectorAll('.weekday-js'); const weekdays = document.querySelectorAll('.weekday-js');
Array.prototype.forEach.call(weekdays, (weekday: HTMLElement) => { Array.prototype.forEach.call(weekdays, (weekday: HTMLElement) => {

View File

@ -17,6 +17,7 @@ export default defineConfig({
rollupOptions: { rollupOptions: {
input: { input: {
main: './main.ts', main: './main.ts',
logbook: './logbook.ts',
// Example for more entry points // Example for more entry points
// test: './src/test.ts', // test: './src/test.ts',
}, },

View File

@ -204,6 +204,7 @@ ORDER BY departure DESC
let mut tx = db.begin().await.unwrap(); let mut tx = db.begin().await.unwrap();
let departure = NaiveDateTime::parse_from_str(&log.departure, "%Y-%m-%dT%H:%M").unwrap(); let departure = NaiveDateTime::parse_from_str(&log.departure, "%Y-%m-%dT%H:%M").unwrap();
println!("@@@@@@ {:?}", log.arrival);
let arrival = log let arrival = log
.arrival .arrival
.map(|a| NaiveDateTime::parse_from_str(&a, "%Y-%m-%dT%H:%M").unwrap()); .map(|a| NaiveDateTime::parse_from_str(&a, "%Y-%m-%dT%H:%M").unwrap());

View File

@ -341,8 +341,9 @@ mod test {
let response = req.dispatch().await; let response = req.dispatch().await;
let text = response.into_string().await.unwrap(); let text = response.into_string().await.unwrap();
println!("{text:?}");
assert!(text.contains("Logbuch")); assert!(text.contains("Logbuch"));
assert!(text.contains("Bootsname: Joe")); assert!(text.contains("Joe"));
} }
#[sqlx::test] #[sqlx::test]
@ -361,7 +362,7 @@ mod test {
let text = response.into_string().await.unwrap(); let text = response.into_string().await.unwrap();
assert!(text.contains("Logbuch")); assert!(text.contains("Logbuch"));
assert!(text.contains("Bootsname: Joe")); assert!(text.contains("Joe"));
} }
#[sqlx::test] #[sqlx::test]

View File

@ -10,7 +10,7 @@
{{ macros::checkbox(label='Gäste erlauben', name='tripdetails.allow_guests') }} {{ macros::checkbox(label='Gäste erlauben', name='tripdetails.allow_guests') }}
{{ macros::checkbox(label='Immer anzeigen', name='tripdetails.always_show') }} {{ macros::checkbox(label='Immer anzeigen', name='tripdetails.always_show') }}
{{ macros::input(label='Anmerkungen', name='tripdetails.notes', type='input') }} {{ macros::input(label='Anmerkungen', name='tripdetails.notes', type='input') }}
{{ macros::select(data=trip_types, select_name='tripdetails.trip_type', default='Reguläre Ausfahrt') }} {{ macros::select(data=trip_types, name='tripdetails.trip_type', default='Reguläre Ausfahrt') }}
<input value="Erstellen" class="w-full btn btn-primary" type="submit"/> <input value="Erstellen" class="w-full btn btn-primary" type="submit"/>
</form> </form>

View File

@ -8,7 +8,7 @@
{{ macros::checkbox(label='Gäste erlauben', name='allow_guests') }} {{ macros::checkbox(label='Gäste erlauben', name='allow_guests') }}
{{ macros::checkbox(label='Immer anzeigen', name='always_show') }} {{ macros::checkbox(label='Immer anzeigen', name='always_show') }}
{{ macros::input(label='Anmerkungen', name='notes', type='input') }} {{ macros::input(label='Anmerkungen', name='notes', type='input') }}
{{ macros::select(data=trip_types, select_name='trip_type', default='Reguläre Ausfahrt') }} {{ macros::select(data=trip_types, name='trip_type', default='Reguläre Ausfahrt') }}
<input value="Erstellen" class="w-full btn btn-primary" type="submit"/> <input value="Erstellen" class="w-full btn btn-primary" type="submit"/>
</form> </form>

View File

@ -8,8 +8,8 @@
{{ macros::input(label="Anzahl Sitze", name="amount_seats", type="number", required=true, min=1) }} {{ macros::input(label="Anzahl Sitze", name="amount_seats", type="number", required=true, min=1) }}
{{ macros::input(label="Baujahr", name="year_built", type="number", min=1950, max=2050) }} {{ macros::input(label="Baujahr", name="year_built", type="number", min=1950, max=2050) }}
{{ macros::input(label="Bootsbauer", name="boatbuilder", type="text") }} {{ macros::input(label="Bootsbauer", name="boatbuilder", type="text") }}
{{ macros::select(data=locations, label='location', select_name='location_id', selected_id=1) }} {{ macros::select(data=locations, label='location', name='location_id', selected_id=1) }}
{{ macros::select(data=users, label='users', select_name='owner', default="Vereinsboot") }} {{ macros::select(data=users, label='users', name='owner', default="Vereinsboot") }}
{{ macros::checkbox(label="Steuerperson steuert nur", name="default_shipmaster_only_steering")}} {{ macros::checkbox(label="Steuerperson steuert nur", name="default_shipmaster_only_steering")}}
{{ macros::checkbox(label="Skull", name="skull", checked=true)}} {{ macros::checkbox(label="Skull", name="skull", checked=true)}}
{{ macros::checkbox(label="Externes Boot (anderer Verein)", name="external")}} {{ macros::checkbox(label="Externes Boot (anderer Verein)", name="external")}}
@ -29,8 +29,8 @@
<div class="grid md:grid-cols-3"> <div class="grid md:grid-cols-3">
{{ macros::input(label='Name', name='name', type='text', value=boat.name) }} {{ macros::input(label='Name', name='name', type='text', value=boat.name) }}
{{ macros::input(label='Amount Seats', name='amount_seats', type='number', min=0, value=boat.amount_seats) }} {{ macros::input(label='Amount Seats', name='amount_seats', type='number', min=0, value=boat.amount_seats) }}
{{ macros::select(data=locations, label='location', select_name='location_id', selected_id=boat.location_id) }} {{ macros::select(data=locations, label='location', name='location_id', selected_id=boat.location_id) }}
{{ macros::select(data=users, label='users', select_name='owner', selected_id=boat.owner, default="Vereinsboot") }} {{ macros::select(data=users, label='users', name='owner', selected_id=boat.owner, default="Vereinsboot") }}
{{ macros::input(label='Baujahr', name='year_built', type='number', min=1950, value=boat.year_built) }} {{ macros::input(label='Baujahr', name='year_built', type='number', min=1950, value=boat.year_built) }}
{{ macros::input(label='Bootsbauer', name='boatbuilder', type='text', value=boat.boatbuilder) }} {{ macros::input(label='Bootsbauer', name='boatbuilder', type='text', value=boat.boatbuilder) }}
{{ macros::checkbox(label='default_shipmaster_only_steering', name='default_shipmaster_only_steering', id=uuid , checked=boat.default_shipmaster_only_steering) }} {{ macros::checkbox(label='default_shipmaster_only_steering', name='default_shipmaster_only_steering', id=uuid , checked=boat.default_shipmaster_only_steering) }}

View File

@ -1,297 +1,252 @@
{# Shows a fancy, optional lists of boats. They are grouped by boat category.
Inputs: boats
Parameters: only_ones: if set, only 1x boats are shown
#}
{% macro show_boats(only_ones) %}
{% if only_ones %}
{% set_global boats = boats | filter(attribute="amount_seats", value=1) %}
{% endif %}
{% for amount_seats, grouped_boats in boats | group_by(attribute="amount_seats") %}
<div class="pb-2">
<div class="bg-gray-100 text-primary-950 text-center text-sm mb-2">
<strong>{{ amount_seats }}x</strong>
</div>
{% for boat in grouped_boats %}
<div id="boat-{{ boat.id }}" class="px-3" {% if boat.damage != 'locked' %} onclick="document.getElementById('boat_id').value={{ boat.id }}; document.getElementById('newrower-max_rower_allowed').innerHTML={{ boat.amount_seats }}; document.getElementById('departure').value = new Date().toISOString().slice(0,16);" {% endif %}>
<span class="status-damage status-damage-{{ boat.damage }}"></span>
<span {% if boat.damage == 'locked' or boat.on_water %} class="opacity-50" {% endif %}>{{ boat.name }}
{% if boat.owner %}
<span class="opacity-50">(privat)</span>
{% endif %}
</span>
</div>
{% endfor %}
</div>
{% endfor %}
{% endmacro show_boats %}
{# Shows the form for creating a new logbook entry. #}
{% macro new(only_ones, allow_any_shipmaster, shipmaster) %} {% macro new(only_ones, allow_any_shipmaster, shipmaster) %}
<form action="/log" method="post" id="form" class="grid grid-cols-2 gap-3"> <form action="/log" method="post" id="form" class="grid grid-cols-2 gap-3" onsubmit="Array.from(this.elements).forEach(e=>!e.value.trim()&&(e.disabled=true));">
{{ log::boat_select(only_ones=only_ones) }} {{ log::boat_select(only_ones=only_ones) }}
{% if allow_any_shipmaster %} {% if allow_any_shipmaster %}
<select name="shipmaster" id="shipmaster" class="input rounded-md h-10"> <select name="shipmaster" id="shipmaster" class="input rounded-md h-10">
<optgroup label="Steuerleute"> <optgroup label="Steuerleute">
{% for cox in coxes %} {% for cox in coxes %}
<option value="{{ cox.id }}" {% if cox.id == shipmaster%} selected {% endif %}>{{ cox.name }}</option> <option value="{{ cox.id }}" {% if cox.id == shipmaster%} selected {% endif %}>{{ cox.name }}</option>
{% endfor %} {% endfor %}
</optgroup> </optgroup>
<optgroup label="Mitglieder"> <optgroup label="Mitglieder">
{% for user in users | filter(attribute="is_cox", value=false) %} {% for user in users | filter(attribute="is_cox", value=false) %}
<option value="{{ user.id }}" {% if user.id == shipmaster%} selected {% endif %}>{{ user.name }}</option> <option value="{{ user.id }}" {% if user.id == shipmaster%} selected {% endif %}>{{ user.name }}</option>
{% endfor %} {% endfor %}
</optgroup> </optgroup>
</select> </select>
{% else %} {% else %}
<input type="hidden" name="shipmaster" value="{{shipmaster}}" /> <input type="hidden" name="shipmaster" value="{{shipmaster}}"/>
{% endif %} {% endif %}
{% if not only_ones %} {% if not only_ones %}
{{ macros::checkbox(label='handgesteuert', name='shipmaster_only_steering') }} {{ macros::checkbox(label='handgesteuert', name='shipmaster_only_steering') }}
{% endif %} {% endif %}
{% if not only_ones %}
{{ log::rower_select(id="newrower", selected=[], class="col-span-2") }}
{% endif %}
<div></div> {% if not only_ones %}
{{ log::rower_select(id="newrower", selected=[], class="col-span-2") }}
{% endif %}
{{ macros::input(label='Abfahrtszeit', name='departure', type='datetime-local', required=true) }} <div></div>
{{ macros::input(label='Ankunftszeit', name='arrival', type='datetime-local') }}
<div> <div>
<label for="destination" class="small text-gray-600">Ziel</label> <label for="destination" class="small text-gray-600">Ziel</label>
<input type="search" class="input rounded-md" list="destinations" placeholder="Destination" name="destination" id="destination" oninput="var inputElement = document.getElementById('destination'); <input type="search" class="input rounded-md" list="destinations" placeholder="Destination" name="destination" id="destination">
var dataList = document.getElementById('destinations'); <datalist id="destinations">
var selectedValue = inputElement.value; {% for distance in distances %}
for (var i = 0; i < dataList.options.length; i++) { <option value="{{ distance.0 }}" distance={{ distance.1 }}/>
if (dataList.options[i].value === selectedValue) { {% endfor %}
var distance = dataList.options[i].getAttribute('distance'); </datalist>
document.getElementById('distance_in_km').value = distance; </div>
break; {{ macros::input(label='Abfahrtszeit', name='departure', type='datetime-local', required=true) }}
} {{ macros::input(label='Ankunftszeit', name='arrival', type='datetime-local') }}
}">
<datalist id="destinations">
{% for distance in distances %}
<option value="{{ distance.0 }}" distance={{ distance.1 }} />
{% endfor %}
</datalist>
</div>
<div class="relative"> <div>
{{ macros::input(label="Distanz", name="distance_in_km", type="number", min=1) }} <label for="destination" class="small text-gray-600">Ziel</label>
<span class="absolute right-0 bottom-0 py-1.5 px-2 bg-white border-0 text-gray-600 ring-1 ring-inset ring-gray-300 rounded-br-md rounded-tr-md">km</span> <input type="search" class="input rounded-md set-distance-js" list="destinations" placeholder="Destination" name="destination" id="destination" data-relation="distance_in_km">
</div> <datalist id="destinations">
{{ macros::input(label="Kommentar", name="comments", type="text", wrapper_class="col-span-2") }} {% for distance in distances %}
<option value="{{ distance.0 }}" distance={{ distance.1 }}/>
{% endfor %}
</datalist>
</div>
<div class="col-span-2"> <div class="relative">
<label for="logtype" class=" small text-gray-600 ">Typ</label> {{ macros::input(label="Distanz", name="distance_in_km", type="number", min=1) }}
{{ macros::select(data=logtypes, select_name='logtype', default="Normal") }} <span class="absolute right-0 bottom-0 py-1.5 px-2 bg-white border-0 text-gray-600 ring-1 ring-inset ring-gray-300 rounded-br-md rounded-tr-md">km</span>
</div> </div>
<input type="submit" value="Ausfahrt starten" class="btn btn-primary w-full col-span-2 m-auto" /> {{ macros::input(label="Kommentar", name="comments", type="text", wrapper_class="col-span-2") }}
<script>
const currentDate = new Date();
const localTime = new Date(currentDate.getTime() - (currentDate.getTimezoneOffset() * 60000));
const formattedDate = localTime.toISOString().slice(0, 16);
// Set the formatted string as the value of the input field <div class="col-span-2">
document.getElementById("departure").value = formattedDate; <label for="logtype" class=" small text-gray-600 ">Typ</label>
</script> {{ macros::select(data=logtypes, name='logtype', default="Normal") }}
</form> </div>
<input type="submit" value="Ausfahrt starten" class="btn btn-primary w-full col-span-2 m-auto"/>
<script src="/public/js/multiselect-dropdown.js" ></script> </form>
<script>
document.getElementById('form').addEventListener('submit', function(e) {
e.preventDefault();
for(let optional_elem of ["arrival", "distance_in_km", "comments", "logtype"]){
let myInput = document.getElementById(optional_elem);
if (myInput.value === '') {
myInput.removeAttribute('name');
}
}
this.submit();
});
</script>
{% endmacro new %} {% endmacro new %}
{% macro show_boats(only_ones) %}
{% if only_ones %}
{% set_global boats = boats | filter(attribute="amount_seats", value=1) %}
{% endif %}
{% for amount_seats, grouped_boats in boats | group_by(attribute="amount_seats") %}
<div class="pb-2">
<div class="bg-gray-100 text-primary-950 text-center text-sm mb-2">
<strong>{{ amount_seats }}x</strong>
</div>
{% for boat in grouped_boats %}
<div id="boat-{{ boat.id }}" {% if boat.damage != 'locked' %} onclick="document.getElementById('boat_id').value='{{ boat.id }}';updateElementsBasedOnSelectedOption()"{% endif %} class="px-3">
<span class="status-damage status-damage-{{ boat.damage }}"></span>
<span {% if boat.damage == 'locked' or boat.on_water %} class="opacity-50" {% endif %}>{{ boat.name }}</span>
</div>
{% endfor %}
</div>
{% endfor %}
<script>
function updateElementsBasedOnSelectedOption() {
var selectElement = document.getElementById('boat_id');
var selectedOption = selectElement.selectedOptions[0];
var shipmaster_only_steering = selectedOption.getAttribute("extra-default_shipmaster_only_steering") === 'true';
document.getElementById('shipmaster_only_steering').checked = shipmaster_only_steering;
document.getElementById('newrower-max_rower_allowed').innerHTML = selectedOption.getAttribute("extra-amount_seats");
console.log(selectElement.selectedOptions[0]);
}
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('boat_id').addEventListener('change', updateElementsBasedOnSelectedOption);
});
document.addEventListener('DOMContentLoaded', updateElementsBasedOnSelectedOption);
</script>
{% endmacro boats %}
{% macro boat_select(only_ones) %} {% macro boat_select(only_ones) %}
{% if not only_ones %} {% if not only_ones %}
{{ macros::select(data=boats, select_name='boat_id', display=["name", " (","amount_seats", " x)"], extras=["default_shipmaster_only_steering", "amount_seats"], class="col-span-2") }} {{ macros::select(data=boats, name='boat_id', display=["name", " (","amount_seats", " x)"], extras=["default_shipmaster_only_steering", "amount_seats"], class="col-span-2") }}
{% else %} {% else %}
{% set ones = boats | filter(attribute="amount_seats", value=1) %} {% set ones = boats | filter(attribute="amount_seats", value=1) %}
{{ macros::select(data=ones, select_name='boat_id', display=["name", " (","amount_seats", " x)"], extras=["default_shipmaster_only_steering", "amount_seats"], class="col-span-2") }} {{ macros::select(data=ones, name='boat_id', display=["name", " (","amount_seats", " x)"], extras=["default_shipmaster_only_steering", "amount_seats"], class="col-span-2") }}
{% endif %} {% endif %}
<script>
function updateElementsBasedOnSelectedOption() {
var selectElement = document.getElementById('boat_id');
var selectedOption = selectElement.selectedOptions[0];
var shipmaster_only_steering = selectedOption.getAttribute("extra-default_shipmaster_only_steering") === 'true';
document.getElementById('shipmaster_only_steering').checked = shipmaster_only_steering;
document.getElementById('newrower-max_rower_allowed').innerHTML = selectedOption.getAttribute("extra-amount_seats");
}
document.getElementById('boat_id').addEventListener('change', updateElementsBasedOnSelectedOption);
document.addEventListener('DOMContentLoaded', updateElementsBasedOnSelectedOption);
</script>
{% endmacro boat_select %} {% endmacro boat_select %}
{% macro rower_select(id, selected, amount_seats='', class='') %}
<div class="{{ class }}">
<select style="width: 100px;" multiple="multiple" name="rowers[]" multiselect-search="true" id="{{id}}" class="w-full">
{% for user in users %}
{% set_global sel = false %}
{% for rower in selected %}
{% if rower.id == user.id %}
{% set_global sel = true %}
{% endif %}
{% endfor %}
<option value="{{ user.id }}" {% if sel %} selected {% endif %}>{{user.name}}</option>
{% endfor %}
</select>
</div>
<div>
<span id="{{id}}-amount_rower_selected"></span>
<span id="{{id}}-max_rower_allowed">{{amount_seats}}</span>
Ruderer auszuwählen
</div>
{% endmacro rower_select %}
{% macro show(log, state, allowed_to_close=false, only_ones) %} {% macro show(log, state, allowed_to_close=false, only_ones) %}
<div class="grid grid-cols-1 gap-3 mb-3 w-full"> <div class="grid grid-cols-1 gap-3 mb-3 w-full">
<div class="pt-2 px-3 {% if not loop.first %} border-t {% endif %}"> <div class="pt-2 px-3 {% if not loop.first %} border-t {% endif %}">
<div class="w-full"> <div class="w-full">
<div class="flex justify-between"> <div class="flex justify-between">
<div> <div>
<strong class="text-primary-900"> <strong class="text-primary-900">
{{ log.departure_timestamp | date(format="%H:%M") }} Uhr {{ log.departure_timestamp | date(format="%H:%M") }}
</strong> Uhr
<small class="text-gray-600">({{ log.boat.name }})</small> </strong>
</div> <small class="text-gray-600">({{ log.boat.name }})</small>
</div>
<a href="#" data-sidebar="true" data-trigger="sidebar" data-header="<strong>{{ log.departure_timestamp | date(format="%H:%M") }} Uhr</strong> ({{ log.boat.name }})" data-body="#log{{ log.id }}" class="inline-block link-primary mr-3">
Details
</a>
</div>
<div>
{% if allowed_to_close and state == "on_water" %}
<a href="#" data-sidebar="true" data-trigger="sidebar" data-header="<strong>{{ log.departure_timestamp | date(format="%H:%M") }} Uhr</strong> ({{ log.boat.name }})" data-body="#close{{ log.id }}" class="btn btn-dark w-full mt-3">
Beenden
</a>
{% endif %}
</div>
<div class="hidden"> <a href="#" data-sidebar="true" data-trigger="sidebar" data-header="<strong>{{ log.departure_timestamp | date(format="%H:%M") }} Uhr</strong> ({{ log.boat.name }})" data-body="#log{{ log.id }}" class="inline-block link-primary mr-3">
{% if allowed_to_close and state == "on_water" %} Details
<div id="close{{ log.id }}"> </a>
{{ log::home(log=log, only_ones=only_ones) }} </div>
</div>
{% endif %}
<div id="log{{ log.id }}">
{% if log.destination %}
{{ log.destination }}
{% endif %}
{% for cox in coxes %}
{% if cox.id == log.shipmaster %}
<p>
<strong>{{ cox.name }}</strong>
</p>
{% endif %}
{% endfor %}
{% for rower in log.rowers %} <div>
<p>{{ rower.name }}</p> {% if allowed_to_close and state == "on_water" %}
{% endfor %} <a href="#" data-sidebar="true" data-trigger="sidebar" data-header="<strong>{{ log.departure_timestamp | date(format="%H:%M") }} Uhr</strong> ({{ log.boat.name }})" data-body="#close{{ log.id }}" class="btn btn-dark w-full mt-3">
</div> Beenden
</div> </a>
</div> {% endif %}
</div> </div>
</div>
{% endmacro show %} <div class="hidden">
{% if allowed_to_close and state == "on_water" %}
<div id="close{{ log.id }}">
{{ log::home(log=log, only_ones=only_ones) }}
</div>
{% endif %}
<div id="log{{ log.id }}">
{% if log.destination %}
{{ log.destination }}
{% endif %}
{% for cox in coxes %}
{% if cox.id == log.shipmaster %}
<p>
<strong>{{ cox.name }}</strong>
</p>
{% endif %}
{% endfor %}
{% for rower in log.rowers %}
<p>{{ rower.name }}</p>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
{% endmacro show %}
{% macro show_old(log, state, allowed_to_close=false, only_ones) %} {% macro show_old(log, state, allowed_to_close=false, only_ones) %}
Bootsname: {{ log.boat.name }}<br /> Bootsname:
Schiffsführer: {{ log.shipmaster_user.name }}<br /> {{ log.boat.name }}<br/>
{% if log.shipmaster_only_steering %} Schiffsführer:
Schiffsführer steuert nur {{ log.shipmaster_user.name }}<br/>
{% endif %} {% if log.shipmaster_only_steering %}
Weggefahren: {{ log.departure }}<br /> Schiffsführer steuert nur
{% if state == "completed" %} {% endif %}
Angekommen: {{ log.arrival}}<br /> Weggefahren:
{% endif %} {{ log.departure }}<br/>
{% set amount_rowers = log.rowers | length %} {% if state == "completed" %}
{% set amount_guests = log.boat.amount_seats - amount_rowers -1 %} Angekommen:
{% if allowed_to_close and state == "on_water" %} {{ log.arrival}}<br/>
{{ log::home(log=log, only_ones=only_ones) }} {% endif %}
{% else %} {% set amount_rowers = log.rowers | length %}
Ziel: {{ log.destination }}<br /> {% set amount_guests = log.boat.amount_seats - amount_rowers -1 %}
{% if state == "completed" %} {% if allowed_to_close and state == "on_water" %}
Km: {{ log.distance_in_km }}<br /> {{ log::home(log=log, only_ones=only_ones) }}
{% endif %} {% else %}
{% if log.comments %} Ziel:
Kommentare: {{ log.comments }}<br /> {{ log.destination }}<br/>
{% endif %} {% if state == "completed" %}
{% if log.logtype %} Km:
Logtype: {{ log.logtype }}<br /> {{ log.distance_in_km }}<br/>
{% endif %} {% endif %}
{% if amount_guests > 0 or log.rowers | length > 0 %} {% if log.comments %}
Ruderer: Kommentare:
{% endif %} {{ log.comments }}<br/>
{% if amount_guests > 0 %} {% endif %}
{{ amount_guests }} Gäste (ohne Account) {% if log.logtype %}
{% endif %} Logtype:
{% for rower in log.rowers %} {{ log.logtype }}<br/>
{{ rower.name }} {% endif %}
{% endfor %} {% if amount_guests > 0 or log.rowers | length > 0 %}
{% endif %} Ruderer:
{% endmacro show_old %} {% endif %}
{% if amount_guests > 0 %}
{{ amount_guests }}
Gäste (ohne Account)
{% endif %}
{% for rower in log.rowers %}
{{ rower.name }}
{% endfor %}
{% endif %}
{% endmacro show_old %}
{% macro home(log, only_ones) %} {% macro home(log, only_ones) %}
<form class="grid grid-cols-1 gap-3" action="/log/{{log.id}}" method="post"> <form class="grid grid-cols-1 gap-3" action="/log/{{log.id}}" method="post">
{% if not only_ones %} {% if not only_ones %}
{{ log::rower_select(id="rowers"~log.id, selected=log.rowers, amount_seats=log.boat.amount_seats) }}
{% endif %} {% endif %}
<div class="relative"> <div class="relative">
<label for="destination" class="small text-gray-600">Ziel</label> <label for="destination" class="small text-gray-600">Ziel</label>
<input class="input rounded-md" type="search" list="destinations" placeholder="Destination" required="required", id="destination-home" name="destination" value="{{log.destination}}" oninput="var inputElement = document.getElementById('destination-home');
var dataList = document.getElementById('destinations');
var selectedValue = inputElement.value;
for (var i = 0; i < dataList.options.length; i++) {
if (dataList.options[i].value === selectedValue) {
var distance = dataList.options[i].getAttribute('distance');
document.getElementById('distance_in_km_home').value = distance;
break;
}
}">
</div>
<div class="relative"> <input class="input rounded-md set-distance-js change-id-js" type="search" list="destinations" placeholder="Destination" required="required" id="destination{{ log.id }}" name="destination" value="{{log.destination}}" data-relation="distance_in_km{{log.id}}"/>
{{ macros::input(label="Distanz", name="distance_in_km", id="distance_in_km_home", type="number", min=0, value=log.distance_in_km, required=true) }} </div>
<span class="absolute right-0 bottom-0 py-1.5 px-2 bg-white border-0 text-gray-600 ring-1 ring-inset ring-gray-300 rounded-br-md rounded-tr-md">km</span>
</div>
{{ macros::input(label="Kommentar", name="comments", type="text", value=log.comments) }}
<div> <div class="relative">
<label for="logtype" class=" small text-gray-600 ">Typ</label> {{ macros::input(label="Distanz", name="distance_in_km", id="distance_in_km" ~ log.id , type="number", min=0, value=log.distance_in_km, required=true, class="rounded-md change-id-js") }}
{{ macros::select(data=logtypes, select_name='logtype', default="Normal", selected_id=log.logtype) }} <span class="absolute right-0 bottom-0 py-1.5 px-2 bg-white border-0 text-gray-600 ring-1 ring-inset ring-gray-300 rounded-br-md rounded-tr-md">km</span>
</div> </div>
<input class="btn btn-primary" type="submit" value="Ausfahrt beenden"/>
</form>
{% endmacro home %}
{{ macros::input(label="Kommentar", name="comments", id="comments" ~ log.id, type="text", value=log.comments, class="rounded-md change-id-js") }}
{% macro rower_select(id, selected, amount_seats='', class='') %} <div>
<div class="{{ class }}"> <label for="logtype" class=" small text-gray-600 ">Typ</label>
<select multiple="multiple" name="rower[]" multiselect-search="true" multiselect-max-items="8" id="{{id}}" onclick="updateSelectedRowersCount{{id}}()" onblur="updateSelectedRowersCount{{id}}()" class="w-full"> {{ macros::select(data=logtypes, name="logtype", id="logtype" ~ log.id, default="Normal", selected_id=log.logtype, class="rounded-md change-id-js") }}
{% for user in users %} </div>
{% set_global sel = false %} <input class="btn btn-primary" type="submit" value="Ausfahrt beenden"/>
{% for rower in selected %} </form>
{% if rower.id == user.id %} {% endmacro home %}
{% set_global sel = true %}
{% endif %}
{% endfor %}
<option value="{{ user.id }}" {% if sel %}selected{% endif %} onmousedown="event.preventDefault();this.selected = !this.selected; return false;">{{user.name}}</option>
{% endfor %}
</select>
<script>
function updateSelectedRowersCount{{id}}() {
document.getElementById('{{id}}-amount_rower_selected').textContent = document.getElementById('{{id}}').selectedOptions.length+1;
}
document.addEventListener('DOMContentLoaded', updateSelectedRowersCount{{id}});
</script>
</div>
<div>
<span id="{{id}}-amount_rower_selected"></span>/<span id="{{id}}-max_rower_allowed">{{amount_seats}}</span> Ruderer ausgewählt
</div>
{% endmacro rower_select %}

View File

@ -74,11 +74,11 @@
</label> </label>
{% endmacro checkbox %} {% endmacro checkbox %}
{% macro select(data, select_name='trip_type', default='', selected_id='', display='', extras='', class='') %} {% macro select(data, name='trip_type', default='', id='', selected_id='', display='', extras='', class='') %}
{% if display == '' %} {% if display == '' %}
{% set display = ["name"] %} {% set display = ["name"] %}
{% endif %} {% endif %}
<select name="{{ select_name }}" id="{{ select_name }}" class="input rounded-md h-10 {{ class }}"> <select name="{{ name }}" {% if id %} id="{{ id }}" {% else %} id="{{ name }}" {% endif %} class="input rounded-md h-10 {{ class }}">
{% if default %} {% if default %}
<option selected value>{{ default }}</option> <option selected value>{{ default }}</option>
{% endif %} {% endif %}

View File

@ -239,7 +239,7 @@
{{ macros::input(label='Anmerkungen', name='notes', type='input', value=trip.notes) }} {{ macros::input(label='Anmerkungen', name='notes', type='input', value=trip.notes) }}
{{ macros::checkbox(label='Immer anzeigen', name='always_show', id=trip.id,checked=trip.always_show) }} {{ macros::checkbox(label='Immer anzeigen', name='always_show', id=trip.id,checked=trip.always_show) }}
{{ macros::checkbox(label='Gesperrt', name='is_locked', id=trip.id,checked=trip.is_locked) }} {{ macros::checkbox(label='Gesperrt', name='is_locked', id=trip.id,checked=trip.is_locked) }}
{{ macros::select(select_name='trip_type', data=trip_types, default='Reguläre Ausfahrt', selected_id=trip.trip_type_id) }} {{ macros::select(name='trip_type', data=trip_types, default='Reguläre Ausfahrt', selected_id=trip.trip_type_id) }}
<input value="Speichern" class="btn btn-primary" type="submit"/> <input value="Speichern" class="btn btn-primary" type="submit"/>
</form> </form>

View File

@ -39,4 +39,6 @@
</div> </div>
{% include "dynamics/sidebar" %} {% include "dynamics/sidebar" %}
<script src="/public/logbook.js"></script>
{% endblock content%} {% endblock content%}

View File

@ -11,33 +11,36 @@
<div class="w-full"> <div class="w-full">
<h1 class="h1">Logbuch</h1> <h1 class="h1">Logbuch</h1>
<div class="w-full grid md:grid-cols-5 gap-3 mt-5"> <div class="w-full grid md:grid-cols-5 gap-3 mt-5">
<div class="bg-white rounded-md hidden md:block shadow"> <div class="bg-white rounded-md hidden md:block shadow">
<h2 class="h2">Boote</h2> <h2 class="h2">Boote</h2>
<div>
{{ log::show_boats(only_ones=false) }}
</div>
</div>
<div class="md:col-span-3 bg-white rounded-md shadow">
<h2 class="h2">Neue Ausfahrt</h2>
<div class="p-3">
{{ log::new(only_ones=loggedin_user.is_cox==false, allow_any_shipmaster=loggedin_user.is_cox, shipmaster=loggedin_user.id) }}
</div>
</div>
<div class="bg-white rounded-md shadow">
<h2 class="h2">Am Wasser</h2>
{% for log in on_water %} <div>
{% if log.shipmaster == loggedin_user.id %} {{ log::show_boats(only_ones=false) }}
{{ log::show(log=log, state="on_water", allowed_to_close=true, only_ones=loggedin_user.is_cox==false) }} </div>
{% else %} </div>
{{ log::show(log=log, state="on_water", only_ones=true) }} <div class="md:col-span-3 bg-white rounded-md shadow">
{% endif %} <h2 class="h2">Neue Ausfahrt</h2>
{% endfor %} <div class="p-3">
</div> {{ log::new(only_ones=loggedin_user.is_cox==false, allow_any_shipmaster=loggedin_user.is_cox, shipmaster=loggedin_user.id) }}
</div> </div>
</div> </div>
<div class="bg-white rounded-md shadow">
<h2 class="h2">Am Wasser</h2>
{% include "dynamics/sidebar" %} {% for log in on_water %}
{% if log.shipmaster == loggedin_user.id %}
{{ log::show(log=log, state="on_water", allowed_to_close=true, only_ones=loggedin_user.is_cox==false) }}
{% else %}
{{ log::show(log=log, state="on_water", only_ones=true) }}
{% endif %}
{% endfor %}
</div>
</div>
</div>
{% include "dynamics/sidebar" %}
<script src="/public/logbook.js"></script>
<script src="/public/js/multiselect-dropdown.js"></script>
{% endblock content%} {% endblock content%}