fix change template mode; fix schedule view; minor fixes

This commit is contained in:
2024-08-09 14:16:51 +02:00
parent 354aa9c3be
commit 7af9eeab61
16 changed files with 240 additions and 132 deletions
+4 -1
View File
@@ -14,4 +14,7 @@ import './styles/main.less';
global.jQuery = global.$ = require('jquery');
require('@fortawesome/fontawesome-free/css/all.min.css');
require('bootstrap');
$('[data-toggle="tooltip"]').tooltip();
$(function () {
$('[data-toggle="tooltip"]').tooltip()
})
+3 -1
View File
@@ -1,9 +1,11 @@
import { startStimulusApp } from '@symfony/stimulus-bridge';
import './services/theme_controller'
import {tmp} from "./services/theme_controller";
// Registers Stimulus controllers from controllers.json and in the controllers/ directory
export const app = startStimulusApp(require.context(
'@symfony/stimulus-bridge/lazy-controller-loader!./controllers',
true,
/\.[jt]sx?$/
));
new tmp()
// register any custom, 3rd party controllers here
@@ -1,4 +1,6 @@
import { Controller } from '@hotwired/stimulus';
import { tmp } from '../services/theme_controller'
export default class extends Controller {
modes;
currentState;
@@ -6,6 +8,8 @@ export default class extends Controller {
this.modes = $(this.element).find('p');
this.currentState = localStorage.getItem('themeMode');
this.changeState()
var tmp1 = new tmp();
tmp1.update();
}
switch(event) {
var mode = event.params.mode;
+30 -32
View File
@@ -1,29 +1,38 @@
(() => {
'use strict'
export class tmp {
constructor() {
const getStoredTheme = () => localStorage.getItem('theme')
const getPreferredTheme = () => {
const storedTheme = getStoredTheme()
if (storedTheme) {
return storedTheme
}
const getStoredTheme = () => localStorage.getItem('theme')
const setStoredTheme = theme => localStorage.setItem('theme', theme)
const getPreferredTheme = () => {
const storedTheme = getStoredTheme()
if (storedTheme) {
return storedTheme
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
}
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
this.setTheme(getPreferredTheme())
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
const storedTheme = getStoredTheme()
if (storedTheme !== 'light' && storedTheme !== 'dark') {
this.setTheme(getPreferredTheme())
}
})
window.addEventListener('DOMContentLoaded', () => {
this.showActiveTheme(getPreferredTheme())
this.update();
})
}
const setTheme = theme => {
setTheme = theme => {
if (theme === 'auto') {
document.documentElement.setAttribute('data-bs-theme', (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'))
} else {
document.documentElement.setAttribute('data-bs-theme', theme)
}
}
setTheme(getPreferredTheme())
const showActiveTheme = (theme, focus = false) => {
setStoredTheme = theme => localStorage.setItem('theme', theme)
showActiveTheme = (theme, focus = false) => {
const themeSwitcher = document.querySelector('#bd-theme')
if (!themeSwitcher) {
@@ -50,26 +59,15 @@
themeSwitcher.focus()
}
}
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
const storedTheme = getStoredTheme()
if (storedTheme !== 'light' && storedTheme !== 'dark') {
setTheme(getPreferredTheme())
}
})
window.addEventListener('DOMContentLoaded', () => {
showActiveTheme(getPreferredTheme())
update() {
document.querySelectorAll('[data-bs-theme-value]')
.forEach(toggle => {
toggle.addEventListener('click', () => {
const theme = toggle.getAttribute('data-bs-theme-value')
console.log(theme)
setStoredTheme(theme)
setTheme(theme)
showActiveTheme(theme, true)
this.setStoredTheme(theme)
this.setTheme(theme)
this.showActiveTheme(theme, true)
})
})
})
})()
}
}
+6 -1
View File
@@ -59,5 +59,10 @@ body {
/* background-color: lightgray;*/
/*}*/
a {
text-decoration: none !important;
//text-decoration: none !important;
}
.spinner-grow.overdue {
position: absolute;
top: 2px;
right: 2px;
}
+8 -11
View File
@@ -9,6 +9,7 @@ use App\Enum\Months;
use App\Enum\ReportStatus;
use App\Enum\ReportTodoEnum;
use App\Helper\MonthHelper;
use App\Services\OverdueReports;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@@ -26,12 +27,6 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
class BaseController extends AbstractController
{
private MonthHelper $monthHelper;
public function __construct(){
$this->monthHelper = new MonthHelper();
}
#[Route('/', name: 'index')]
public function index(): Response
{
@@ -42,12 +37,13 @@ class BaseController extends AbstractController
}
#[Route('/reports/{monthId}', name: 'app_base')]
#[IsGranted('reportView')]
public function reportsIndex(EntityManagerInterface $entityManager, int $monthId = 0) : Response
public function reportsIndex(EntityManagerInterface $entityManager, OverdueReports $overdueReports, int $monthId = 0) : Response
{
$monthHelper = new MonthHelper($overdueReports);
$isOverdue = false;
if ($monthId > -1) {
$monthCurrent = $this->monthHelper->getCurrentMonth($monthId);
$reportsAll = $entityManager->getRepository(Reports::class)->findAllInMonth($monthCurrent);
$monthCurrentDate = $monthHelper->getCurrentMonthDate($monthId);
$reportsAll = $entityManager->getRepository(Reports::class)->findAllInMonth($monthCurrentDate);
} else {
$reportsAll = $entityManager->getRepository(Reports::class)->findAllOverdue();
$isOverdue = true;
@@ -67,10 +63,11 @@ class BaseController extends AbstractController
ksort($reports);
return $this->render('reports/list.html.twig', [
'reportsGroup' => $reports,
'months' => $this->monthHelper->takeMonths(),
'currentMonth' => $monthCurrent ?? null,
'months' => $monthHelper->takeMonths(),
'currentMonth' => $monthCurrentDate ?? null,
'reportToDoList' => ReportTodoEnum::cases(),
'isOverdue' => $isOverdue,
'countOverdueLeft' => $overdueReports->getLeftCount()
]);
}
}
+11 -8
View File
@@ -22,7 +22,6 @@ class ReportsController extends AbstractController
$token = $request->get("token");
if ($this->isCsrfTokenValid('report-status', $token)) {
$reportsService->setClient($report->getClient());
$isDone = false;
if ($request->get("unDone")){
$todo = $entityManager->getRepository(ReportsTodo::class)->findOneBy([
"report" => $report->getId(),
@@ -30,8 +29,12 @@ class ReportsController extends AbstractController
]);
$todo->setDeleted(true);
$entityManager->persist($todo);
$report->setDone(false);
} else {
foreach (ReportTodoEnum::cases() as $case) {
if (!$request->get($case->value)) {
continue;
}
$todo = $entityManager->getRepository(ReportsTodo::class)->findOneBy([
"report" => $report->getId(),
"name" => $case->value
@@ -40,19 +43,19 @@ class ReportsController extends AbstractController
$todo = new ReportsTodo();
$todo->setReport($report);
$todo->setName($case);
}
if ($request->get($case->value) !== null) {
$todo->setDeleted(false);
} else {
$todo->setDeleted(true);
$todo->setDeleted(!$todo->isDeleted());
}
if ($todo->getName() === ReportTodoEnum::COMPLETE && !$todo->isDeleted()) {
$isDone = true;
if ($todo->getName() === ReportTodoEnum::COMPLETE) {
if ($todo->isDeleted()) {
$report->setDone(false);
} else {
$report->setDone(true);
}
}
$entityManager->persist($todo);
}
}
$report->setDone($isDone);
$entityManager->persist($report);
$entityManager->flush();
$reportsService->tryAddNextReport();
@@ -18,6 +18,7 @@ class ScheduleController extends AbstractController
{
if ($typeId == 1) {
$schedulesTmp = $entityManager->getRepository(Schedule::class)->findAllCurrent();
$isOverdue = $entityManager->getRepository(Schedule::class)->findAllOverdue(true);
} else {
$schedulesTmp = $entityManager->getRepository(Schedule::class)->findAllOverdue();
}
@@ -25,16 +26,15 @@ class ScheduleController extends AbstractController
return $this->render('schedule/index.html.twig', [
'typeId' => $typeId,
'schedules' => $schedulesTmp,
'isOverdue' => $isOverdue ?? false,
]);
}
#[Route('/schedule_status', name: 'app_schedule_status')]
public function setDone(EntityManagerInterface $entityManager, Request $request): Response
#[Route('/schedule_status/{id}', name: 'app_schedule_status', methods: ['POST'])]
public function setDone(EntityManagerInterface $entityManager, Request $request, Schedule $schedule): Response
{
$scheduleId = $request->getPayload()->get('scheduleId');
$token = $request->getPayload()->get("token");
if ($scheduleId && $this->isCsrfTokenValid('schedule-status', $token)) {
$schedule = $entityManager->getRepository(Schedule::class)->find($scheduleId);
$token = $request->get("token");
if ($this->isCsrfTokenValid('schedule-status', $token)) {
$isDone = true;
if ($schedule->isDone()) {
$isDone = false;
+11
View File
@@ -18,4 +18,15 @@ enum ScheduleStatus: int
ScheduleStatus::COMPLETED => 'success',
};
}
public function borderColor(): string
{
return match ($this) {
ScheduleStatus::TODO => '',
ScheduleStatus::INCOMING => 'warning',
ScheduleStatus::OVERDUE => 'danger',
ScheduleStatus::COMPLETED => 'success',
};
}
}
+20 -5
View File
@@ -1,38 +1,53 @@
<?php
namespace App\Helper;
use App\Services\OverdueReports;
class MonthHelper
{
public function __construct(private readonly OverdueReports $overdueReports){}
public function takeMonths() : array
{
$startDate = new \DateTime("-6 months");
$startDate->modify("first day of this month");
$return = [];
$overdueCounts = $this->overdueReports->getList();
for ($i=1; $i<=11; $i++) {
$tmp = clone $startDate;
$tmp->modify("+$i month");
$return[$i] = $tmp;
$return[$i] = [
'date' => $tmp,
'overdueCount' => 0
];
$key = $tmp->format('Y-m');
if (isset($overdueCounts[$key])) {
$return[$i]['overdueCount'] = $overdueCounts[$key];
unset($overdueCounts[$key]);
}
}
if (count($overdueCounts) > 0) {
$this->overdueReports->setLeftCount(array_sum($overdueCounts));
}
return $return;
}
public function getCurrentMonth(int $monthId) : \DateTime
public function getCurrentMonthDate(int $monthId) : \DateTime
{
$months = $this->takeMonths();
if ($monthId==0) {
$currentMonth = intval(date("n"));
foreach ($months as $mId => $monthObj) {
if ($monthObj->format("m") == $currentMonth) {
$date = $monthObj['date']->format('m');
if ($date == $currentMonth) {
$monthCurrent = $monthObj;
$monthId = $mId;
break;
}
}
} else {
$monthCurrent = $months[$monthId];
}
return $monthCurrent;
return $monthCurrent['date'];
}
}
+29 -5
View File
@@ -11,25 +11,49 @@ use Doctrine\Persistence\ManagerRegistry;
*/
class ScheduleRepository extends ServiceEntityRepository
{
private const _OVERDUE_DAYS_START = 15;
private const _OVERDUE_DAYS_END = 30;
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Schedule::class);
}
public function findAllOverdue()
public function findAllOverdue(bool $onlyCount = false) : array|int
{
$dateEnd = new \DateTime("now");
$dateEnd->modify("-".self::_OVERDUE_DAYS_START." days");
$reports = $this->createQueryBuilder('s')
->where('s.isDone = :isDone')
->andWhere('s.dateEnd < :dateEnd')
// ->andWhere('s.isDelete = :isDelete')
->setParameter('isDone', 0)
// ->setParameter('isDelete', 0)
->setParameter('dateEnd', $dateEnd);
if ($onlyCount) {
$reports->select('COUNT(s.id)');
return $reports->getQuery()->getSingleScalarResult();
}
return $reports->getQuery()->getResult();
}
public function isOverdue(): bool
{
$dateEnd = new \DateTime("now");
$dateEnd->modify("-".self::_OVERDUE_DAYS_START." days");
$query = $this->createQueryBuilder('s')
->select('count(s.id)')
->where('s.isDone = :isDone')
->andWhere('s.dateEnd < :dateEnd')
// ->andWhere('s.isDelete = :isDelete')
->setParameter('isDone', 0)
// ->setParameter('isDelete', 0)
->setParameter('dateEnd', $dateEnd)
->getQuery()
->getResult();
->getSingleScalarResult();
return $reports;
trigger_error(var_export($query,true));
}
/**
@@ -39,9 +63,9 @@ class ScheduleRepository extends ServiceEntityRepository
{
$date = new \DateTime();
$dateStart = clone $date;
$dateStart->modify("-15 days");
$dateStart->modify("-".self::_OVERDUE_DAYS_START." days");
$dateEnd = clone $date;
$dateEnd->modify("+30 days");
$dateEnd->modify("+".self::_OVERDUE_DAYS_END." days");
return $this->createQueryBuilder('r')
->where('r.dateEnd >= :dateStart')
->andWhere('r.dateEnd <= :dateEnd')
+49
View File
@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace App\Services;
use App\Entity\Reports;
use Doctrine\ORM\EntityManager;
class OverdueReports
{
private array $list;
private int $leftCount = 0;
public function __construct(private readonly EntityManager $entity){
$this->list = $this->takeOverdueList();
}
public function getList(): array
{
return $this->list;
}
public function setLeftCount(int $leftCount): void
{
$this->leftCount = $leftCount;
}
public function getLeftCount(): int
{
return $this->leftCount;
}
private function takeOverdueList() : array
{
$reports = $this->entity->getRepository(Reports::class)->findAllOverdue();
if (!$reports) {
return [];
}
$toReturn = [];
/** @var Reports $report */
foreach ($reports as $report) {
$date = $report->getDateStart()->format('Y-m');
if (!array_key_exists($date, $toReturn)) {
$toReturn[$date] = 1;
} else {
$toReturn[$date]++;
}
}
return $toReturn;
}
}
@@ -1,31 +1,20 @@
{% macro month_menu(routeName, months, currentMonth) %}
{% macro month_menu(routeName, months, currentMonth, countOverdueLeft) %}
<div class="row reports-months-all">
{# <div class="col">#}
{# <div class="card">#}
{# <a href="{{ path(routeName, {monthId:-1}) }}" class="btn {% if currentMonth is null %}btn-success{% else %}btn-secondary{% endif %}">Zaległe</a>#}
{# </div>#}
{# </div>#}
{# {% for id,month in months %}#}
{# {% set isCurrent = currentMonth is not null and month | date("Y-m") == currentMonth | date("Y-m") %}#}
{# <div class="col col-xxl-1 col-xl-2 col-lg-2 col-md-3 col-sm-3 col-4">#}
{# <div class="card">#}
{# <a href="{{ path(routeName,{monthId: id}) }}" class="btn {% if isCurrent %}btn-success{% else %}btn-secondary{% endif %}">#}
{# {% if routeName=='app_schedule' %}#}
{# {{ id }}#}
{# {% else %}#}
{# {{ month | date("Y-m") }}#}
{# {% endif %}#}
{# </a>#}
{# </div>#}
{# </div>#}
{# {% endfor %}#}
<ul class="nav nav-underline nav-fill">
<li class="nav-item">
<li class="nav-item position-relative">
<a href="{{ path(routeName, {monthId:-1}) }}" class="nav-link {% if currentMonth is null %}active{% endif %}">Zaległe</a>
{% if countOverdueLeft > 0 %}
<div class="spinner-grow spinner-grow-sm text-danger overdue"></div>
{% endif %}
</li>
{% for id,month in months %}
{% for id,obj in months %}
{% set month = obj.date %}
{% set isCurrent = currentMonth is not null and month | date("Y-m") == currentMonth | date("Y-m") %}
<li class="nav-item">
<li class="nav-item position-relative"
{% if obj.overdueCount > 0 %}
data-toggle="tooltip" data-bs-placement="bottom" title="Zaległe sprawozdania do zrobienia"
{% endif %}
>
<a class="nav-link {% if isCurrent %} active{% endif %}" href="{{ path(routeName,{monthId: id}) }}">
{% if routeName=='app_schedule' %}
{{ id }}
@@ -33,6 +22,9 @@
{{ month | date("Y-m") }}
{% endif %}
</a>
{% if obj.overdueCount > 0 %}
<div class="spinner-grow spinner-grow-sm text-danger overdue"></div>
{% endif %}
</li>
{% endfor %}
</ul>
+1 -1
View File
@@ -2,7 +2,7 @@
{% import 'navigation/switch_months.html.twig' as navigation %}
{% import 'reports/listInclude.html.twig' as sets %}
{% block body %}
{{ navigation.month_menu('app_base',months,currentMonth) }}
{{ navigation.month_menu('app_base',months,currentMonth,countOverdueLeft) }}
<div class="
row
d-flex
+21 -14
View File
@@ -3,20 +3,27 @@
<input type="hidden" name="token" value="{{ csrf_token('report-status') }}">
<div class="btn-group" role="group" aria-label="Todos">
{% for todo in reportToDoList %}
<input onchange="this.form.submit()"
name="{{ todo.value }}"
type="checkbox"
class="btn-check"
id="checkboxToDo{{ todo.value }}Id{{ report.id }}"
{% if report.isReportsTodo(todo) %}
checked="checked"
{% endif %}
{% if not is_granted('reportEdit') %}
disabled
{% endif %}
autocomplete="off"
>
<label class="btn btn-outline-{{ reportEnum.checkboxColor }} d-flex align-items-center"
<button type="submit" class="btn-check" name="{{ todo.value }}" value='1' id="checkboxToDo{{ todo.value }}Id{{ report.id }}"></button>
{# <input onchange="this.form.submit()"#}
{# name="{{ todo.value }}"#}
{# type="checkbox"#}
{# class="btn-check"#}
{# id="checkboxToDo{{ todo.value }}Id{{ report.id }}"#}
{# {% if report.isReportsTodo(todo) %}#}
{# checked="checked"#}
{# {% endif %}#}
{# {% if not is_granted('reportEdit') %}#}
{# disabled#}
{# {% endif %}#}
{# autocomplete="off"#}
{# >#}
<label class="btn
{% if report.isReportsTodo(todo) %}
btn-{{ reportEnum.checkboxColor }}
{% else %}
btn-outline-{{ reportEnum.checkboxColor }}
{% endif %}
d-flex align-items-center"
for="checkboxToDo{{ todo.value }}Id{{ report.id }}"
data-toggle="tooltip" data-placement="bottom" title="{{ todo.takeLang }}">
<i class="fa fa-solid fa-{{ todo.takeIcon }}"> </i>
+22 -24
View File
@@ -2,44 +2,42 @@
{% import 'navigation/switch_months.html.twig' as navigation %}
{% block title %}Harmonogramy{% endblock %}
{% block body %}
{# {{ navigation.month_menu('app_schedule',months,currentMonth) }}#}
<div class="row row-cols-2 reports-months-all">
<div class="col">
<a href="{{ path('app_schedule', {typeId:2}) }}" class="card text-center text-white {% if typeId == 2 %}bg-primary{% else %}bg-secondary{% endif %}">
<div class="card-title"><h2>Zaległe</h2></div>
</a>
{# <a href="{{ path('app_schedule', {monthId:-1}) }}" class="btn {% if currentMonth is null %}btn-success{% else %}btn-secondary{% endif %}">Zaległe</a>#}
</div>
<div class="col">
<a href="{{ path('app_schedule', {typeId:1}) }}" class="card text-center text-white {% if typeId == 1 %}bg-primary{% else %}bg-secondary{% endif %}">
<div class="card-title"><h2>Aktualne</h2></div>
</a>
{# <a href="{{ path('app_schedule', {monthId:-1}) }}" class="btn {% if currentMonth is null %}btn-success{% else %}btn-secondary{% endif %}">Zaległe</a>#}
</div>
{# <div class="col">#}
{# <a href="{{ path('app_schedule', {monthId:1}) }}" class="btn {% if currentMonth is null %}btn-success{% else %}btn-secondary{% endif %}">Aktualne</a>#}
{# </div>#}
<div class="row reports-months-all">
<ul class="nav nav-underline nav-fill">
<li class="nav-item position-relative">
<a href="{{ path('app_schedule', {typeId:2}) }}" class="nav-link {% if typeId == 2 %}active{% endif %}">Zaległe</a>
{% if isOverdue %}
<div class="spinner-grow spinner-grow-sm text-danger overdue"></div>
{% endif %}
</li>
<li class="nav-item">
<a href="{{ path('app_schedule', {typeId:1}) }}" class="nav-link {% if typeId == 1 %}active{% endif %}">Aktualne</a>
</li>
</ul>
</div>
<div class="row row-cols-auto reports-all">
<div class="row row-cols-auto schedule-all">
{% for schedule in schedules %}
<div class="col">
<div class="card text-white bg-{{ schedule.getStatus.backgroundColor }}">
<div class="card border-{{ schedule.getStatus.borderColor }}">
<div class="card-body">
<h5 class="card-title">
{% if is_granted('clientView') %}
<a href="{{ path('app_client',{id: schedule.client.id}) }}" class="link-dark">{{ schedule.client.strName }}</a>
<a href="{{ path('app_client',{id: schedule.client.id}) }}">{{ schedule.client.strName }}</a>
{% else %}
<div class="link-dark">{{ schedule.client.strName }}</div>
{% endif %}
</h5>
{% if enum(schedule.getStatus, 'OVERDUE') %}
<h6 class="card-subtitle text-muted text-danger-emphasis">Czas minął: {{ schedule.getTimeLeft }} dni</h6>
<div class="spinner-grow spinner-grow-sm text-danger overdue"></div>
{% else %}
<h6 class="card-subtitle text-muted">Pozostały czas: {{ schedule.getTimeLeft }} dni</h6>
{% endif %}
</div>
<div class="card-footer">
<form action="{{ path('app_schedule_status') }}" method="post">
<form action="{{ path('app_schedule_status',{id:schedule.id}) }}" method="post">
<input type="hidden" name="token" value="{{ csrf_token('schedule-status') }}">
<input type="hidden" name="scheduleId" value="{{ schedule.id }}">
<button type="submit" class="btn btn-success">Wysłano</button>
<button type="submit" class="btn btn-outline-success w-100">Wysłano</button>
</form>
</div>
</div>