Compare commits
5 commits
7897621621
...
6967285ad7
Author | SHA1 | Date | |
---|---|---|---|
6967285ad7 | |||
b57ab05558 | |||
9fc198e3e3 | |||
5225fff0ef | |||
f4d2ddf354 |
6 changed files with 15 additions and 158 deletions
|
@ -13,10 +13,8 @@ import './styles/emoji-footprint.css';
|
||||||
import './javascript/theme.js';
|
import './javascript/theme.js';
|
||||||
import './javascript/emoji-footprint.js';
|
import './javascript/emoji-footprint.js';
|
||||||
import './javascript/modes.js';
|
import './javascript/modes.js';
|
||||||
import htmx from 'htmx.org';
|
|
||||||
import { initNumberInputs } from './javascript/numberInputs.js';
|
import { initNumberInputs } from './javascript/numberInputs.js';
|
||||||
import { initRadioState } from './javascript/radioState.js';
|
import { initRadioState } from './javascript/radioState.js';
|
||||||
window.htmx = htmx;
|
|
||||||
|
|
||||||
// Initialize everything when DOM is ready
|
// Initialize everything when DOM is ready
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
|
@ -2,21 +2,22 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
use Symfony\Config\FrameworkConfig;
|
|
||||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||||
|
|
||||||
return static function (
|
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||||
ContainerConfigurator $containerConfigurator,
|
$containerConfigurator->extension('framework', [
|
||||||
FrameworkConfig $frameworkConfig,
|
'asset_mapper' => [
|
||||||
): void {
|
'paths' => [
|
||||||
$frameworkConfig
|
'assets/',
|
||||||
->assetMapper()
|
],
|
||||||
->missingImportMode('strict')
|
'missing_import_mode' => 'strict',
|
||||||
->importmapPolyfill(false)
|
],
|
||||||
->path('assets/', true);
|
]);
|
||||||
if ($containerConfigurator->env() === 'prod') {
|
if ($containerConfigurator->env() === 'prod') {
|
||||||
$frameworkConfig
|
$containerConfigurator->extension('framework', [
|
||||||
->assetMapper()
|
'asset_mapper' => [
|
||||||
->missingImportMode('ignore');
|
'missing_import_mode' => 'warn',
|
||||||
|
],
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -37,7 +37,4 @@ return [
|
||||||
'chart.js/auto' => [
|
'chart.js/auto' => [
|
||||||
'version' => '4.5.0',
|
'version' => '4.5.0',
|
||||||
],
|
],
|
||||||
'htmx.org' => [
|
|
||||||
'version' => '2.0.6',
|
|
||||||
],
|
|
||||||
];
|
];
|
||||||
|
|
|
@ -110,19 +110,4 @@ final class DrinkTypeController extends AbstractController
|
||||||
|
|
||||||
return $this->redirectToRoute('app_drink_type_index', [], Response::HTTP_SEE_OTHER);
|
return $this->redirectToRoute('app_drink_type_index', [], Response::HTTP_SEE_OTHER);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route(path: '/{id}/history-chart', name: 'app_drink_type_history_chart', methods: ['GET'])]
|
|
||||||
public function historyChart(
|
|
||||||
DrinkType $drinkType,
|
|
||||||
GetStockHistory $getStockHistory,
|
|
||||||
GetWantedHistory $getWantedHistory,
|
|
||||||
): Response {
|
|
||||||
return $this->render('components/history_chart_with_dismiss.html.twig', [
|
|
||||||
'stock_history' => $getStockHistory($drinkType),
|
|
||||||
'wanted_history' => $getWantedHistory($drinkType),
|
|
||||||
'chart_id' => 'stockHistoryChart_' . $drinkType->getId(),
|
|
||||||
'title' => $drinkType->getName() . ' History',
|
|
||||||
'drink_type_id' => $drinkType->getId(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,118 +0,0 @@
|
||||||
<tr id="history-row-{{ drink_type_id }}">
|
|
||||||
<td colspan="3">
|
|
||||||
<div class="card mb-3">
|
|
||||||
<div class="card-header d-flex justify-content-between align-items-center">
|
|
||||||
<h5 class="card-title mb-0">{{ title }}</h5>
|
|
||||||
<button type="button" class="btn btn-sm btn-danger"
|
|
||||||
onclick="document.getElementById('history-row-{{ drink_type_id }}').style.display = 'none';">
|
|
||||||
❌ Dismiss
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div style="height: 300px; position: relative;">
|
|
||||||
<canvas id="{{ chart_id }}"></canvas>
|
|
||||||
</div>
|
|
||||||
<script type="module">
|
|
||||||
import { Chart } from 'chart.js/auto';
|
|
||||||
|
|
||||||
// Create a unified set of dates from both datasets
|
|
||||||
{% set all_dates = [] %}
|
|
||||||
{% for record in stock_history %}
|
|
||||||
{% set date_str = record.changeDate|date('Y-m-d H:i') %}
|
|
||||||
{% if date_str not in all_dates %}
|
|
||||||
{% set all_dates = all_dates|merge([date_str]) %}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
{% for record in wanted_history %}
|
|
||||||
{% set date_str = record.changeDate|date('Y-m-d H:i') %}
|
|
||||||
{% if date_str not in all_dates %}
|
|
||||||
{% set all_dates = all_dates|merge([date_str]) %}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
// Sort dates chronologically
|
|
||||||
{% set all_dates = all_dates|sort %}
|
|
||||||
|
|
||||||
// Create date-indexed maps for both datasets
|
|
||||||
{% set stock_map = {} %}
|
|
||||||
{% for record in stock_history %}
|
|
||||||
{% set date_str = record.changeDate|date('Y-m-d H:i') %}
|
|
||||||
{% set stock_map = stock_map|merge({(date_str): record.newValue}) %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{% set wanted_map = {} %}
|
|
||||||
{% for record in wanted_history %}
|
|
||||||
{% set date_str = record.changeDate|date('Y-m-d H:i') %}
|
|
||||||
{% set wanted_map = wanted_map|merge({(date_str): record.newValue}) %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
// Prepare data arrays with values aligned to dates
|
|
||||||
{% set stock_data = [] %}
|
|
||||||
{% set wanted_data = [] %}
|
|
||||||
|
|
||||||
{% for date in all_dates %}
|
|
||||||
{% if date in stock_map|keys %}
|
|
||||||
{% set stock_data = stock_data|merge([stock_map[date]]) %}
|
|
||||||
{% else %}
|
|
||||||
{% set stock_data = stock_data|merge(['null']) %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if date in wanted_map|keys %}
|
|
||||||
{% set wanted_data = wanted_data|merge([wanted_map[date]]) %}
|
|
||||||
{% else %}
|
|
||||||
{% set wanted_data = wanted_data|merge(['null']) %}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
new Chart(document.getElementById('{{ chart_id }}'), {
|
|
||||||
type: 'line',
|
|
||||||
data: {
|
|
||||||
labels: [{% for date in all_dates %}'{{ date }}'{{ not loop.last ? ',' }}{% endfor %}],
|
|
||||||
datasets: [{
|
|
||||||
label: 'Stock History',
|
|
||||||
data: [{{ stock_data|join(',') }}],
|
|
||||||
borderColor: 'rgb(75, 192, 192)',
|
|
||||||
tension: 0.1,
|
|
||||||
spanGaps: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Wanted Stock History',
|
|
||||||
data: [{{ wanted_data|join(',') }}],
|
|
||||||
borderColor: 'rgb(255, 99, 132)',
|
|
||||||
tension: 0.1,
|
|
||||||
spanGaps: true
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
maintainAspectRatio: false,
|
|
||||||
plugins: {
|
|
||||||
legend: {
|
|
||||||
position: 'top',
|
|
||||||
labels: {
|
|
||||||
boxWidth: 12,
|
|
||||||
padding: 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
scales: {
|
|
||||||
y: {
|
|
||||||
beginAtZero: true,
|
|
||||||
ticks: {
|
|
||||||
maxTicksLimit: 6
|
|
||||||
}
|
|
||||||
},
|
|
||||||
x: {
|
|
||||||
ticks: {
|
|
||||||
maxTicksLimit: 8,
|
|
||||||
maxRotation: 45
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
|
@ -37,19 +37,13 @@
|
||||||
{{ form_widget(drinkTypeForm.name) }}
|
{{ form_widget(drinkTypeForm.name) }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-sm btn-info"
|
lol
|
||||||
hx-get="{{ path('app_drink_type_history_chart', {'id': drinkTypeForm.vars.value.id}) }}"
|
|
||||||
hx-target="#history-row-{{ drinkTypeForm.vars.value.id }}"
|
|
||||||
hx-swap="outerHTML"
|
|
||||||
type="button"
|
|
||||||
>📊 Show History</button>
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ form_widget(drinkTypeForm.wantedStock) }}
|
{{ form_widget(drinkTypeForm.wantedStock) }}
|
||||||
{{ form_errors(drinkTypeForm.wantedStock) }}
|
{{ form_errors(drinkTypeForm.wantedStock) }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr id="history-row-{{ drinkTypeForm.vars.value.id }}" style="display: none;" class="history-row"></tr>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue