added taskreport, commentTask feature
This commit is contained in:
parent
ddfbed1020
commit
10d6f96ea7
13
index.html
13
index.html
@ -49,6 +49,7 @@
|
||||
|
||||
<!-- Timer Picker -->
|
||||
<!-- Flatpickr CSS -->
|
||||
<link rel="stylesheet" href="/assets/vendor/libs/flatpickr/flatpickr.css" />
|
||||
|
||||
|
||||
|
||||
@ -84,7 +85,7 @@
|
||||
<script src="/assets/vendor/libs/select2/select2.js"></script>
|
||||
<script src="/assets/vendor/libs/apex-charts/apexcharts.js"></script>
|
||||
<script src="/assets/vendor/libs/jquery-timepicker/jquery-timepicker.js" ></script>
|
||||
|
||||
<script src="/assets/vendor/libs/flatpickr/flatpickr.js" ></script>
|
||||
<!-- Main JS -->
|
||||
<script src="/assets/js/main.js"></script>
|
||||
|
||||
@ -102,17 +103,7 @@
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.min.js"></script> -->
|
||||
|
||||
<!-- Flatpickr JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
|
||||
|
||||
<script>
|
||||
// Initialize flatpickr for 12-hour time format with AM/PM
|
||||
flatpickr("#timePicker", {
|
||||
enableTime: true,
|
||||
noCalendar: true,
|
||||
time_24hr: false, // Disable 24-hour format
|
||||
dateFormat: "h:i K", // 12-hour format with AM/PM
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
906
public/assets/vendor/libs/flatpickr/flatpickr.css
vendored
Normal file
906
public/assets/vendor/libs/flatpickr/flatpickr.css
vendored
Normal file
@ -0,0 +1,906 @@
|
||||
.flatpickr-calendar {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
padding-bottom: 2px;
|
||||
max-height: 0;
|
||||
border: 0;
|
||||
text-align: center;
|
||||
opacity: 0;
|
||||
animation: none;
|
||||
outline: 0;
|
||||
touch-action: manipulation;
|
||||
line-height: 1.375;
|
||||
font-size: 0.9375rem;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
.flatpickr-calendar.open, .flatpickr-calendar.inline {
|
||||
visibility: visible;
|
||||
overflow: visible;
|
||||
max-height: 640px;
|
||||
opacity: 1;
|
||||
}
|
||||
.flatpickr-calendar.open {
|
||||
display: inline-block;
|
||||
}
|
||||
.flatpickr-calendar.animate.open {
|
||||
animation: fpFadeInDown 300ms cubic-bezier(0.23, 1, 0.32, 1);
|
||||
}
|
||||
.flatpickr-calendar:not(.inline):not(.open) {
|
||||
display: none !important;
|
||||
}
|
||||
.flatpickr-calendar.inline {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
display: block;
|
||||
}
|
||||
.flatpickr-calendar.static {
|
||||
position: absolute;
|
||||
top: calc(100% + 2px);
|
||||
}
|
||||
.flatpickr-calendar.static.open {
|
||||
z-index: 999;
|
||||
display: block;
|
||||
}
|
||||
.flatpickr-calendar.hasWeeks {
|
||||
width: auto;
|
||||
}
|
||||
html:not([dir=rtl]) .flatpickr-calendar.hasWeeks .flatpickr-days {
|
||||
border-bottom-left-radius: 0 !important;
|
||||
}
|
||||
[dir=rtl] .flatpickr-calendar.hasWeeks .flatpickr-days {
|
||||
border-bottom-right-radius: 0 !important;
|
||||
}
|
||||
.flatpickr-calendar.hasTime {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.flatpickr-calendar.hasTime .flatpickr-time {
|
||||
height: 40px;
|
||||
}
|
||||
.flatpickr-calendar.noCalendar.hasTime .flatpickr-time {
|
||||
height: auto;
|
||||
}
|
||||
.flatpickr-calendar input[type=number] {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
.flatpickr-calendar input[type=number]::-webkit-inner-spin-button,
|
||||
.flatpickr-calendar input[type=number]::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.flatpickr-wrapper {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.flatpickr-month {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
height: 3rem;
|
||||
text-align: center;
|
||||
line-height: 1;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.flatpickr-prev-month,
|
||||
.flatpickr-next-month {
|
||||
position: absolute;
|
||||
top: 0.75rem;
|
||||
z-index: 3;
|
||||
padding: 0 0.41rem;
|
||||
height: 1.875rem;
|
||||
width: 1.875rem;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
border-radius: 0.375rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.flatpickr-prev-month svg,
|
||||
.flatpickr-next-month svg {
|
||||
stroke-width: 2;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.flatpickr-prev-month i,
|
||||
.flatpickr-next-month i {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.flatpickr-prev-month.flatpickr-prev-month {
|
||||
left: 1rem;
|
||||
}
|
||||
[dir=rtl] .flatpickr-prev-month {
|
||||
right: 1rem;
|
||||
left: auto;
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.flatpickr-next-month.flatpickr-prev-month {
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
.flatpickr-next-month.flatpickr-next-month {
|
||||
right: 1rem;
|
||||
}
|
||||
[dir=rtl] .flatpickr-next-month {
|
||||
right: auto;
|
||||
left: 1rem;
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.flatpickr-prev-month:hover,
|
||||
.flatpickr-next-month:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.flatpickr-prev-month svg,
|
||||
.flatpickr-next-month svg {
|
||||
width: 0.6rem;
|
||||
}
|
||||
|
||||
.flatpickr-prev-month svg path,
|
||||
.flatpickr-next-month svg path {
|
||||
transition: fill 0.1s;
|
||||
fill: inherit;
|
||||
}
|
||||
|
||||
.numInputWrapper {
|
||||
position: relative;
|
||||
height: auto;
|
||||
}
|
||||
.numInputWrapper :hover {
|
||||
background: transparent;
|
||||
}
|
||||
.numInputWrapper input,
|
||||
.numInputWrapper span {
|
||||
display: inline-block;
|
||||
}
|
||||
.numInputWrapper input {
|
||||
width: 100%;
|
||||
}
|
||||
.numInputWrapper span {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
width: 14px;
|
||||
height: 50%;
|
||||
line-height: 1;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
[dir=rtl] .numInputWrapper span {
|
||||
right: auto;
|
||||
left: 0;
|
||||
}
|
||||
.numInputWrapper span:hover {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.numInputWrapper span:active {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.numInputWrapper span:after {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
.numInputWrapper span.arrowUp {
|
||||
top: 0;
|
||||
}
|
||||
.numInputWrapper span.arrowUp:after {
|
||||
border-right: 4px solid transparent;
|
||||
border-bottom: 4px solid rgba(72, 72, 72, 0.6);
|
||||
border-left: 4px solid transparent;
|
||||
}
|
||||
.numInputWrapper span.arrowDown {
|
||||
top: 50%;
|
||||
}
|
||||
.numInputWrapper span.arrowDown:after {
|
||||
border-top: 4px solid rgba(72, 72, 72, 0.6);
|
||||
border-right: 4px solid transparent;
|
||||
border-left: 4px solid transparent;
|
||||
}
|
||||
.numInputWrapper span svg {
|
||||
width: inherit;
|
||||
height: auto;
|
||||
}
|
||||
.numInputWrapper span svg path {
|
||||
fill: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.numInputWrapper:hover {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.numInputWrapper:hover span {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.flatpickr-current-month {
|
||||
position: absolute;
|
||||
left: 12.5%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.25rem;
|
||||
width: 75%;
|
||||
height: 2.5rem;
|
||||
text-align: center;
|
||||
font-weight: 300;
|
||||
line-height: 1;
|
||||
padding: 0.9rem 0 0 0;
|
||||
transform: translate3d(0px, 0px, 0px);
|
||||
}
|
||||
.flatpickr-current-month .flatpickr-monthDropdown-months,
|
||||
.flatpickr-current-month input.cur-year {
|
||||
outline: none;
|
||||
vertical-align: middle !important;
|
||||
font-weight: 400;
|
||||
font-size: inherit;
|
||||
font-family: inherit;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
.flatpickr-current-month .flatpickr-monthDropdown-months:not(:first-child),
|
||||
.flatpickr-current-month input.cur-year:not(:first-child) {
|
||||
padding: 0 0 0 0.5ch;
|
||||
}
|
||||
.flatpickr-current-month .numInputWrapper {
|
||||
display: inline-block;
|
||||
width: 6ch;
|
||||
}
|
||||
.flatpickr-current-month .flatpickr-monthDropdown-months {
|
||||
appearance: menulist;
|
||||
cursor: pointer;
|
||||
height: 2.25rem;
|
||||
position: relative;
|
||||
width: auto;
|
||||
font-size: 0.9375rem;
|
||||
}
|
||||
.flatpickr-current-month input.cur-year {
|
||||
margin: 0;
|
||||
height: 1.2rem;
|
||||
cursor: default;
|
||||
}
|
||||
[dir=rtl] .flatpickr-current-month input.cur-year {
|
||||
padding-right: 0.5ch;
|
||||
padding-left: 0;
|
||||
}
|
||||
.flatpickr-current-month input.cur-year:focus {
|
||||
outline: 0;
|
||||
}
|
||||
.flatpickr-current-month input.cur-year[disabled], .flatpickr-current-month input.cur-year[disabled]:hover {
|
||||
background: transparent;
|
||||
pointer-events: none;
|
||||
}
|
||||
.flatpickr-current-month input.cur-year[disabled] {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.flatpickr-weekdaycontainer {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 0.25rem 0.6rem;
|
||||
}
|
||||
|
||||
.flatpickr-weekdays {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
align-items: center;
|
||||
max-width: 17.5rem;
|
||||
width: 100%;
|
||||
height: 2.25rem;
|
||||
text-align: center;
|
||||
margin-bottom: 0.125rem;
|
||||
}
|
||||
|
||||
span.flatpickr-weekday {
|
||||
display: block;
|
||||
flex: 1;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
line-height: 1;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.dayContainer,
|
||||
.flatpickr-weeks {
|
||||
padding: 1px 0 0 0;
|
||||
}
|
||||
|
||||
.flatpickr-days {
|
||||
position: relative;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
width: auto !important;
|
||||
}
|
||||
.flatpickr-days:focus {
|
||||
outline: 0;
|
||||
}
|
||||
.flatpickr-calendar.hasTime .flatpickr-days {
|
||||
border-bottom: 0 !important;
|
||||
border-bottom-right-radius: 0 !important;
|
||||
border-bottom-left-radius: 0 !important;
|
||||
}
|
||||
|
||||
.dayContainer {
|
||||
display: inline-block;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-around;
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
min-width: 15.75rem;
|
||||
max-width: 15.75rem;
|
||||
width: 15.75rem;
|
||||
outline: 0;
|
||||
opacity: 1;
|
||||
transform: translate3d(0px, 0px, 0px);
|
||||
}
|
||||
|
||||
.flatpickr-day {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
flex-basis: 14.2857143%;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
max-width: 2.25rem;
|
||||
width: 15.2857143%;
|
||||
height: 2.25rem;
|
||||
border: 1px solid transparent;
|
||||
background: none;
|
||||
text-align: center;
|
||||
font-weight: 400;
|
||||
line-height: calc(2.25rem - 2px);
|
||||
cursor: pointer;
|
||||
}
|
||||
.flatpickr-day.inRange, .flatpickr-day.prevMonthDay.inRange, .flatpickr-day.nextMonthDay.inRange, .flatpickr-day.today.inRange, .flatpickr-day.prevMonthDay.today.inRange, .flatpickr-day.nextMonthDay.today.inRange, .flatpickr-day:hover, .flatpickr-day.prevMonthDay:hover, .flatpickr-day.nextMonthDay:hover, .flatpickr-day:focus, .flatpickr-day.prevMonthDay:focus, .flatpickr-day.nextMonthDay:focus {
|
||||
outline: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
.flatpickr-day.inRange:not(.startRange):not(.endRange) {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
.flatpickr-day.disabled, .flatpickr-day.flatpickr-disabled, .flatpickr-day.flatpickr-disabled.today, .flatpickr-day.disabled:hover, .flatpickr-day.flatpickr-disabled:hover, .flatpickr-day.flatpickr-disabled.today:hover {
|
||||
border-color: transparent;
|
||||
background: transparent !important;
|
||||
cursor: default;
|
||||
pointer-events: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
.flatpickr-day.prevMonthDay, .flatpickr-day.nextMonthDay {
|
||||
border-color: transparent;
|
||||
background: transparent;
|
||||
cursor: default;
|
||||
}
|
||||
.flatpickr-day.notAllowed, .flatpickr-day.notAllowed.prevMonthDay, .flatpickr-day.notAllowed.nextMonthDay {
|
||||
border-color: transparent;
|
||||
background: transparent;
|
||||
cursor: default;
|
||||
}
|
||||
.flatpickr-day.week.selected {
|
||||
border-radius: 0;
|
||||
}
|
||||
html:not([dir=rtl]) .flatpickr-day.selected.startRange, html:not([dir=rtl]) .flatpickr-day.startRange.startRange, html:not([dir=rtl]) .flatpickr-day.endRange.startRange {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
html:not([dir=rtl]) .flatpickr-day.selected.endRange, html:not([dir=rtl]) .flatpickr-day.startRange.endRange, html:not([dir=rtl]) .flatpickr-day.endRange.endRange {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
[dir=rtl] .flatpickr-day.selected.startRange, [dir=rtl] .flatpickr-day.startRange.startRange, [dir=rtl] .flatpickr-day.endRange.startRange {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
[dir=rtl] .flatpickr-day.selected.endRange, [dir=rtl] .flatpickr-day.startRange.endRange, [dir=rtl] .flatpickr-day.endRange.endRange {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.flatpickr-weekwrapper {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
}
|
||||
.flatpickr-weekwrapper .flatpickr-weeks {
|
||||
background-clip: padding-box !important;
|
||||
}
|
||||
html:not([dir=rtl]) .flatpickr-weekwrapper .flatpickr-weeks .flatpickr-weeks {
|
||||
border-bottom-right-radius: 0 !important;
|
||||
}
|
||||
[dir=rtl] .flatpickr-weekwrapper .flatpickr-weeks .flatpickr-weeks {
|
||||
border-bottom-left-radius: 0 !important;
|
||||
}
|
||||
.flatpickr-weekwrapper .flatpickr-weeks .flatpickr-day {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.flatpickr-weekwrapper .flatpickr-calendar.hasTime .flatpickr-weeks {
|
||||
border-bottom: 0 !important;
|
||||
border-bottom-right-radius: 0 !important;
|
||||
border-bottom-left-radius: 0 !important;
|
||||
}
|
||||
.flatpickr-weekwrapper .flatpickr-weekday {
|
||||
float: none;
|
||||
width: 100%;
|
||||
line-height: 2.25rem;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
.flatpickr-weekwrapper span.flatpickr-day {
|
||||
display: block;
|
||||
max-width: none;
|
||||
width: 2.25rem;
|
||||
background: none !important;
|
||||
}
|
||||
|
||||
.flatpickr-calendar.hasTime .flatpickr-weeks {
|
||||
border-bottom: 0 !important;
|
||||
border-bottom-left-radius: 0 !important;
|
||||
border-bottom-right-radius: 0 !important;
|
||||
}
|
||||
|
||||
.flatpickr-innerContainer {
|
||||
display: block;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
html:not([dir=rtl]) .flatpickr-innerContainer:has(.flatpickr-weeks) .flatpickr-weeks {
|
||||
padding-left: 0.445rem;
|
||||
}
|
||||
[dir=rtl] .flatpickr-innerContainer:has(.flatpickr-weeks) .flatpickr-weeks {
|
||||
padding-left: 0.445rem;
|
||||
}
|
||||
[dir=rtl] .flatpickr-innerContainer:has(.flatpickr-weeks) .flatpickr-weekdaycontainer {
|
||||
padding-left: 0.625rem;
|
||||
}
|
||||
.flatpickr-innerContainer:has(.flatpickr-weeks) .flatpickr-weekwrapper .flatpickr-weekday {
|
||||
padding-left: 0.445rem;
|
||||
}
|
||||
[dir=rtl] .flatpickr-innerContainer:has(.flatpickr-weeks) .flatpickr-weekwrapper {
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
|
||||
.flatpickr-rContainer {
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.flatpickr-time {
|
||||
display: block;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
max-height: 40px;
|
||||
height: 0;
|
||||
outline: 0;
|
||||
background-clip: padding-box !important;
|
||||
text-align: center;
|
||||
line-height: 40px;
|
||||
}
|
||||
.flatpickr-time:after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
.flatpickr-time .numInputWrapper {
|
||||
float: left;
|
||||
flex: 1;
|
||||
width: 40%;
|
||||
height: 40px;
|
||||
}
|
||||
.flatpickr-time.hasSeconds .numInputWrapper {
|
||||
width: 26%;
|
||||
}
|
||||
.flatpickr-time.time24hr .numInputWrapper {
|
||||
width: 49%;
|
||||
}
|
||||
.flatpickr-time input {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: inherit;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
text-align: center;
|
||||
line-height: inherit;
|
||||
cursor: pointer;
|
||||
font-size: 0.9375rem;
|
||||
}
|
||||
.flatpickr-time input.flatpickr-hour, .flatpickr-time input.flatpickr-minute, .flatpickr-time input.flatpickr-second {
|
||||
font-weight: 400;
|
||||
}
|
||||
.flatpickr-time input:focus {
|
||||
outline: 0;
|
||||
border: 0;
|
||||
}
|
||||
.flatpickr-time .flatpickr-time-separator,
|
||||
.flatpickr-time .flatpickr-am-pm {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
align-self: center;
|
||||
width: 2%;
|
||||
height: inherit;
|
||||
line-height: inherit;
|
||||
user-select: none;
|
||||
}
|
||||
.flatpickr-time .flatpickr-am-pm {
|
||||
width: 18%;
|
||||
outline: 0;
|
||||
text-align: center;
|
||||
font-weight: normal;
|
||||
cursor: pointer;
|
||||
}
|
||||
.flatpickr-time .flatpickr-am-pm:hover {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.flatpickr-calendar.noCalendar .flatpickr-time {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.flatpickr-calendar:not(.noCalendar) .flatpickr-time {
|
||||
border-top: 0;
|
||||
border-top-left-radius: 0 !important;
|
||||
border-top-right-radius: 0 !important;
|
||||
}
|
||||
|
||||
.flatpickr-input[readonly] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@-webkit-keyframes fpFadeInDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translate3d(0, -20px, 0);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
}
|
||||
@-moz-keyframes fpFadeInDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translate3d(0, -20px, 0);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
}
|
||||
@keyframes fpFadeInDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translate3d(0, -20px, 0);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
}
|
||||
.light-style .flatpickr-calendar {
|
||||
background: #fff;
|
||||
}
|
||||
.light-style .flatpickr-prev-month,
|
||||
.light-style .flatpickr-next-month {
|
||||
background-color: #edeef0;
|
||||
}
|
||||
.light-style .flatpickr-prev-month svg,
|
||||
.light-style .flatpickr-next-month svg {
|
||||
fill: #646e78;
|
||||
stroke: #646e78;
|
||||
}
|
||||
.light-style .flatpickr-calendar,
|
||||
.light-style .flatpickr-days {
|
||||
width: calc(16.75rem + 0 * 2px) !important;
|
||||
}
|
||||
.light-style .flatpickr-calendar {
|
||||
background-color: #fff;
|
||||
border-radius: 0.375rem !important;
|
||||
}
|
||||
.light-style:not([dir=rtl]) .flatpickr-calendar.hasWeeks {
|
||||
width: calc(19rem + 0 * 3px + 0.35rem) !important;
|
||||
}
|
||||
.light-style[dir=rtl] .flatpickr-calendar.hasWeeks {
|
||||
width: calc(19rem + 0 * 3px + 1rem) !important;
|
||||
}
|
||||
.light-style .flatpickr-calendar.open {
|
||||
z-index: 1091;
|
||||
}
|
||||
.light-style .flatpickr-input[readonly],
|
||||
.light-style .flatpickr-input ~ .form-control[readonly] {
|
||||
background: transparent;
|
||||
}
|
||||
.light-style .flatpickr-days {
|
||||
background: #fff;
|
||||
padding: 0.25rem 0.5rem 0.5rem;
|
||||
border: 0 solid #e4e6e8;
|
||||
border-top: 0;
|
||||
background-clip: padding-box;
|
||||
border-bottom-right-radius: 0.375rem;
|
||||
border-bottom-left-radius: 0.375rem;
|
||||
}
|
||||
.light-style:not([dir=rtl]) .flatpickr-calendar.hasWeeks .flatpickr-days {
|
||||
border-left: 0;
|
||||
padding-left: calc(0.5rem + 0px);
|
||||
box-shadow: 0 0 0 #e4e6e8 inset;
|
||||
}
|
||||
.light-style[dir=rtl] .flatpickr-calendar.hasWeeks .flatpickr-days {
|
||||
border-right: 0;
|
||||
padding-right: calc(0.5rem + 0px);
|
||||
box-shadow: 0 0 0 #e4e6e8 inset;
|
||||
}
|
||||
.light-style .flatpickr-calendar {
|
||||
line-height: 1.375;
|
||||
font-size: 0.9375rem;
|
||||
box-shadow: 0 0.25rem 0.75rem 0 rgba(34, 48, 62, 0.14);
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
.light-style .flatpickr-calendar.hasTime:not(.noCalendar):not(.hasTime) .flatpickr-time {
|
||||
display: none !important;
|
||||
}
|
||||
.light-style .flatpickr-calendar.hasTime .flatpickr-time {
|
||||
box-shadow: 0 1px 0 #e4e6e8 inset;
|
||||
}
|
||||
.light-style .flatpickr-monthDropdown-months {
|
||||
color: #384551;
|
||||
}
|
||||
.light-style .flatpickr-current-month {
|
||||
font-size: 112%;
|
||||
color: #384551;
|
||||
}
|
||||
.light-style .flatpickr-current-month .cur-month,
|
||||
.light-style .flatpickr-current-month .cur-year {
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 400;
|
||||
color: #384551;
|
||||
}
|
||||
.light-style .flatpickr-month,
|
||||
.light-style span.flatpickr-weekday,
|
||||
.light-style .flatpickr-weekdays {
|
||||
background: #fff;
|
||||
}
|
||||
.light-style .flatpickr-month {
|
||||
border-top-left-radius: 0.375rem;
|
||||
border-top-right-radius: 0.375rem;
|
||||
}
|
||||
.light-style .flatpickr-month option.flatpickr-monthDropdown-month {
|
||||
color: #384551;
|
||||
background: transparent;
|
||||
}
|
||||
.light-style span.flatpickr-weekday {
|
||||
color: #384551;
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.light-style .flatpickr-day {
|
||||
color: #384551;
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
.light-style .flatpickr-day:hover, .light-style .flatpickr-day:focus, .light-style .flatpickr-day.prevMonthDay:hover, .light-style .flatpickr-day.nextMonthDay:hover, .light-style .flatpickr-day.today:hover, .light-style .flatpickr-day.prevMonthDay:focus, .light-style .flatpickr-day.nextMonthDay:focus, .light-style .flatpickr-day.today:focus {
|
||||
color: #384551;
|
||||
background: #f2f3f3;
|
||||
}
|
||||
.light-style .flatpickr-day:hover:not(.today), .light-style .flatpickr-day:focus:not(.today), .light-style .flatpickr-day.prevMonthDay:hover:not(.today), .light-style .flatpickr-day.nextMonthDay:hover:not(.today), .light-style .flatpickr-day.today:hover:not(.today), .light-style .flatpickr-day.prevMonthDay:focus:not(.today), .light-style .flatpickr-day.nextMonthDay:focus:not(.today), .light-style .flatpickr-day.today:focus:not(.today) {
|
||||
border-color: transparent;
|
||||
}
|
||||
.light-style .flatpickr-day.prevMonthDay, .light-style .flatpickr-day.nextMonthDay, .light-style .flatpickr-day.flatpickr-disabled {
|
||||
color: #a7acb2 !important;
|
||||
}
|
||||
.light-style .flatpickr-day.prevMonthDay.today, .light-style .flatpickr-day.nextMonthDay.today, .light-style .flatpickr-day.flatpickr-disabled.today {
|
||||
border: none;
|
||||
}
|
||||
.light-style .flatpickr-day.disabled {
|
||||
color: #a7acb2 !important;
|
||||
}
|
||||
.light-style .flatpickr-day.selected.startRange.endRange {
|
||||
border-radius: 0.375rem !important;
|
||||
}
|
||||
.light-style .flatpickr-weeks {
|
||||
border-bottom: 0 solid #e4e6e8;
|
||||
border-left: 0 solid #e4e6e8;
|
||||
background: #fff;
|
||||
border-bottom-right-radius: 0.375rem;
|
||||
border-bottom-left-radius: 0.375rem;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
.light-style .flatpickr-weeks .flatpickr-day {
|
||||
color: #384551;
|
||||
}
|
||||
.light-style[dir=rtl] .flatpickr-weeks {
|
||||
border-right: 0 solid #e4e6e8;
|
||||
border-left: 0;
|
||||
border-bottom-right-radius: 0.375rem;
|
||||
border-bottom-left-radius: 0.375rem;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
.light-style .flatpickr-time {
|
||||
border: 0 solid #e4e6e8;
|
||||
background: #fff;
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
.light-style .flatpickr-time input {
|
||||
color: #646e78;
|
||||
font-size: 0.9375rem;
|
||||
}
|
||||
.light-style .flatpickr-time .numInputWrapper span.arrowUp:after {
|
||||
border-bottom-color: #a7acb2;
|
||||
}
|
||||
.light-style .flatpickr-time .numInputWrapper span.arrowDown:after {
|
||||
border-top-color: #a7acb2;
|
||||
}
|
||||
.light-style .flatpickr-time .flatpickr-am-pm {
|
||||
color: #646e78;
|
||||
}
|
||||
.light-style .flatpickr-time .flatpickr-time-separator {
|
||||
color: #646e78;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.dark-style .flatpickr-calendar {
|
||||
background: #2b2c40;
|
||||
}
|
||||
.dark-style .flatpickr-prev-month,
|
||||
.dark-style .flatpickr-next-month {
|
||||
background-color: rgba(230, 230, 241, 0.08);
|
||||
}
|
||||
.dark-style .flatpickr-prev-month svg,
|
||||
.dark-style .flatpickr-next-month svg {
|
||||
fill: #b2b2c4;
|
||||
stroke: #b2b2c4;
|
||||
}
|
||||
.dark-style .flatpickr-calendar,
|
||||
.dark-style .flatpickr-days {
|
||||
width: calc(16.75rem + 0 * 2px) !important;
|
||||
}
|
||||
.dark-style:not([dir=rtl]) .flatpickr-calendar.hasWeeks {
|
||||
width: calc(19rem + 0 * 3px + 0.355rem) !important;
|
||||
}
|
||||
.dark-style[dir=rtl] .flatpickr-calendar.hasWeeks {
|
||||
width: calc(19rem + 0 * 3px + 1rem) !important;
|
||||
}
|
||||
.dark-style .flatpickr-calendar.open {
|
||||
z-index: 1091;
|
||||
}
|
||||
.dark-style .flatpickr-input:not(.is-invalid):not(.is-valid) ~ .form-control:disabled,
|
||||
.dark-style .flatpickr-input:not(.is-invalid):not(.is-valid)[readonly],
|
||||
.dark-style .flatpickr-input:not(.is-invalid):not(.is-valid) ~ .form-control[readonly] {
|
||||
background-color: transparent;
|
||||
}
|
||||
.dark-style .flatpickr-days {
|
||||
border: 0 solid #4e4f6c;
|
||||
border-top: 0;
|
||||
padding: 0.25rem 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
background: #2b2c40;
|
||||
background-clip: padding-box;
|
||||
border-bottom-right-radius: 0.375rem;
|
||||
border-bottom-left-radius: 0.375rem;
|
||||
}
|
||||
.dark-style:not([dir=rtl]) .flatpickr-calendar.hasWeeks .flatpickr-days {
|
||||
border-left: 0;
|
||||
padding-left: calc(0.5rem + 0px);
|
||||
box-shadow: 0 0 0 #4e4f6c inset;
|
||||
}
|
||||
.dark-style[dir=rtl] .flatpickr-calendar.hasWeeks .flatpickr-days {
|
||||
border-right: 0;
|
||||
padding-right: calc(0.5rem + 0px);
|
||||
box-shadow: 0 0 0 #4e4f6c inset;
|
||||
}
|
||||
.dark-style .flatpickr-calendar {
|
||||
line-height: 1.375;
|
||||
font-size: 0.9375rem;
|
||||
box-shadow: 0 0.25rem 0.75rem 0 rgba(20, 20, 29, 0.24);
|
||||
background-color: #2b2c40;
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
.dark-style .flatpickr-calendar.hasTime:not(.noCalendar):not(.hasTime) .flatpickr-time {
|
||||
display: none !important;
|
||||
}
|
||||
.dark-style .flatpickr-calendar.hasTime .flatpickr-time {
|
||||
box-shadow: 0 1px 0 #4e4f6c inset;
|
||||
}
|
||||
.dark-style .flatpickr-month,
|
||||
.dark-style span.flatpickr-weekday,
|
||||
.dark-style .flatpickr-weekdays {
|
||||
background: #2b2c40;
|
||||
}
|
||||
.dark-style .flatpickr-month {
|
||||
border-top-left-radius: 0.375rem;
|
||||
border-top-right-radius: 0.375rem;
|
||||
}
|
||||
.dark-style .flatpickr-month option.flatpickr-monthDropdown-month {
|
||||
color: #b2b2c4;
|
||||
background: #2b2c40;
|
||||
}
|
||||
.dark-style .flatpickr-monthDropdown-months {
|
||||
color: #d5d5e2;
|
||||
}
|
||||
.dark-style .flatpickr-current-month {
|
||||
font-size: 112%;
|
||||
color: #d5d5e2;
|
||||
}
|
||||
.dark-style .flatpickr-current-month .cur-month,
|
||||
.dark-style .flatpickr-current-month .cur-year {
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 400;
|
||||
color: #d5d5e2;
|
||||
}
|
||||
.dark-style span.flatpickr-weekday {
|
||||
font-size: 0.8125rem;
|
||||
color: #d5d5e2;
|
||||
}
|
||||
.dark-style .flatpickr-day {
|
||||
color: #d5d5e2;
|
||||
font-weight: 500;
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
.dark-style .flatpickr-day:hover, .dark-style .flatpickr-day:focus, .dark-style .flatpickr-day.nextMonthDay:hover, .dark-style .flatpickr-day.prevMonthDay:hover, .dark-style .flatpickr-day.today:hover, .dark-style .flatpickr-day.nextMonthDay:focus, .dark-style .flatpickr-day.prevMonthDay:focus, .dark-style .flatpickr-day.today:focus {
|
||||
border-color: transparent;
|
||||
color: #d5d5e2;
|
||||
background: #434463;
|
||||
}
|
||||
.dark-style .flatpickr-day.nextMonthDay, .dark-style .flatpickr-day.prevMonthDay, .dark-style .flatpickr-day.flatpickr-disabled {
|
||||
color: #7e7f96 !important;
|
||||
}
|
||||
.dark-style .flatpickr-day.nextMonthDay.today, .dark-style .flatpickr-day.prevMonthDay.today, .dark-style .flatpickr-day.flatpickr-disabled.today {
|
||||
border: 0;
|
||||
}
|
||||
.dark-style .flatpickr-day.selected.startRange.endRange {
|
||||
border-radius: 0.375rem !important;
|
||||
}
|
||||
.dark-style .flatpickr-day.disabled {
|
||||
color: #7e7f96 !important;
|
||||
}
|
||||
.dark-style .flatpickr-weeks {
|
||||
border-bottom: 0 solid #4e4f6c;
|
||||
border-left: 0 solid #4e4f6c;
|
||||
background: #2b2c40;
|
||||
border-bottom-right-radius: 0.375rem;
|
||||
border-bottom-left-radius: 0.375rem;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
.dark-style .flatpickr-weeks .flatpickr-day {
|
||||
color: #d5d5e2;
|
||||
}
|
||||
.dark-style[dir=rtl] .flatpickr-weeks {
|
||||
border-right: 0 solid #4e4f6c;
|
||||
border-left: 0;
|
||||
}
|
||||
.dark-style .flatpickr-time {
|
||||
border: 0 solid #4e4f6c;
|
||||
background: #2b2c40;
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
.dark-style .flatpickr-time input {
|
||||
color: #b2b2c4;
|
||||
}
|
||||
.dark-style .flatpickr-time .numInputWrapper span.arrowUp:after {
|
||||
border-bottom-color: #7e7f96;
|
||||
}
|
||||
.dark-style .flatpickr-time .numInputWrapper span.arrowDown:after {
|
||||
border-top-color: #7e7f96;
|
||||
}
|
||||
.dark-style .flatpickr-time .flatpickr-am-pm {
|
||||
color: #b2b2c4;
|
||||
}
|
||||
.dark-style .flatpickr-time .flatpickr-time-separator {
|
||||
color: #b2b2c4;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
144
public/assets/vendor/libs/flatpickr/flatpickr.js
vendored
Normal file
144
public/assets/vendor/libs/flatpickr/flatpickr.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -9,7 +9,7 @@ import { useNavigate } from "react-router-dom";
|
||||
|
||||
const Attendance = ( {attendance, getRole, handleModalData} ) =>
|
||||
{
|
||||
console.log(attendance)
|
||||
|
||||
const { currentPage, totalPages, currentItems, paginate } = usePagination(attendance, 5);
|
||||
const [loading,setLoading] = useState(false);
|
||||
const navigate = useNavigate()
|
||||
@ -47,7 +47,6 @@ console.log(attendance)
|
||||
></Avatar>
|
||||
<div className="d-flex flex-column">
|
||||
<a
|
||||
// href="#"
|
||||
onClick={(e) =>navigate(`/employee/${item.employeeId}?for=attendance`)}
|
||||
className="text-heading text-truncate cursor-pointer"
|
||||
>
|
||||
@ -68,7 +67,7 @@ console.log(attendance)
|
||||
<td>{item.checkInTime ? convertShortTime(item.checkInTime):"--"}</td>
|
||||
<td>{item.checkOutTime ? convertShortTime(item.checkOutTime):"--"}</td>
|
||||
|
||||
<td className="mx-24" >
|
||||
<td className="text-center" >
|
||||
<RenderAttendanceStatus attendanceData={item} handleModalData={handleModalData} Tab={1} currentDate={null}/>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -4,7 +4,7 @@ import AttendLogs from './AttendLogs'
|
||||
import Confirmation from './Confirmation'
|
||||
|
||||
const AttendanceModel = ({modelConfig,closeModal,handleSubmitForm}) => {
|
||||
console.log(modelConfig)
|
||||
|
||||
return (
|
||||
<div className={`modal-dialog modal-md modal-simple ${modelConfig.type === "view" ? "modal-lg":"modal-md"}`} >
|
||||
<div className="modal-content">
|
||||
|
@ -21,11 +21,15 @@ const InfraPlanning = () =>
|
||||
{
|
||||
const {profile: LoggedUser} = useProfile()
|
||||
const dispatch = useDispatch()
|
||||
const {projects,loading:project_listLoader,error:projects_error} = useProjects()
|
||||
|
||||
const selectedProject = useSelector((store)=>store.localVariables.projectId)
|
||||
const ManageInfra = useHasUserPermission( MANAGE_PROJECT_INFRA )
|
||||
const {projects,loading:project_listLoader,error:projects_error} = useProjects()
|
||||
const {projects_Details, loading: project_deatilsLoader, error: project_error} = useProjectDetails(selectedProject)
|
||||
|
||||
useEffect( () =>
|
||||
{
|
||||
dispatch(setProjectId(projects[0]?.id))
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="col-md-12 col-lg-12 col-xl-12 order-0 mb-4">
|
||||
@ -93,8 +97,13 @@ const InfraPlanning = () =>
|
||||
</button>
|
||||
</div> */}
|
||||
</div>
|
||||
<div className="row ">
|
||||
<InfraTable buildings={projects_Details?.buildings}/>
|
||||
<div className="row ">
|
||||
{project_deatilsLoader && ( <p>Loading...</p> )}
|
||||
{( !project_deatilsLoader && projects_Details?.buildings.length === 0 ) && ( <p>No Result Found</p> )}
|
||||
|
||||
|
||||
|
||||
{(!project_deatilsLoader && projects_Details?.buildings?.length > 0) && (<InfraTable buildings={projects_Details?.buildings}/>)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -23,7 +23,7 @@ const RenderAttendanceStatus = ({ attendanceData, handleModalData,Tab,currentDat
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-auto d-flex gap-2 align-items-center justify-content-between">
|
||||
<div className="d-flex justify-content-center">
|
||||
<button
|
||||
type="button"
|
||||
className={`btn btn-xs ${color}`}
|
||||
@ -39,7 +39,7 @@ const RenderAttendanceStatus = ({ attendanceData, handleModalData,Tab,currentDat
|
||||
{attendanceData?.checkInTime && (
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-xs btn-success"
|
||||
className="btn btn-xs btn-success ms-2"
|
||||
tabIndex="0"
|
||||
aria-controls="DataTables_Table_0"
|
||||
data-bs-toggle="modal"
|
||||
|
180
src/components/Activities/ReportTask.jsx
Normal file
180
src/components/Activities/ReportTask.jsx
Normal file
@ -0,0 +1,180 @@
|
||||
import React, { useState } from "react";
|
||||
import { formatDate } from "../../utils/dateUtils";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
import showToast from "../../services/toastService";
|
||||
import { TasksRepository } from "../../repositories/TaskRepository";
|
||||
|
||||
export const ReportTask = ({ report,closeModal,refetch }) => {
|
||||
const [ loading, setloading ] = useState( false );
|
||||
|
||||
|
||||
const schema = z.object({
|
||||
completedTask: z
|
||||
.number()
|
||||
.min(1, "Completed Work must be at least 1")
|
||||
.max(
|
||||
report?.plannedTask,
|
||||
`Completed Work cannot exceed ${report?.plannedTask}`
|
||||
)
|
||||
.int("Completed Work must be an integer")
|
||||
.positive("Completed Work must be a positive number")
|
||||
.optional(),
|
||||
comment: z.string().min(1, "Comment cannot be empty"),
|
||||
});
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
} = useForm({
|
||||
resolver: zodResolver(schema),
|
||||
});
|
||||
|
||||
const onSubmit = async (data) => {
|
||||
try
|
||||
{
|
||||
setloading(true)
|
||||
const reportData = {
|
||||
...data,
|
||||
id: report?.id,
|
||||
reportedDate: new Date().toISOString(),
|
||||
};
|
||||
|
||||
|
||||
let response = await TasksRepository.reportTsak( reportData )
|
||||
showToast( "succesfully", "success" )
|
||||
refetch()
|
||||
closeModal()
|
||||
|
||||
} catch (error) {
|
||||
showToast("Somthing wrog", "error");
|
||||
}
|
||||
};
|
||||
const handleClose = () => {
|
||||
closeModal();
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
|
||||
<div className="modal-dialog modal-md modal-simple report-task-modal" role="document">
|
||||
<div className="modal-content">
|
||||
<div className="modal-body px-1">
|
||||
<button
|
||||
type="button"
|
||||
className="btn-close"
|
||||
|
||||
onClick={handleClose}
|
||||
aria-label="Close"
|
||||
></button>
|
||||
|
||||
<div className="container m-0">
|
||||
<div className="d-flex justify-content-between">
|
||||
|
||||
<figure class="text-start p-0 m-0">
|
||||
<blockquote class="blockquote">
|
||||
<small> Assigned Date : {formatDate(report?.assignmentDate)}</small>
|
||||
</blockquote>
|
||||
</figure>
|
||||
<figure class="text-end p-0 m-0">
|
||||
<blockquote class="blockquote">
|
||||
<small>Assigned By</small>
|
||||
</blockquote>
|
||||
<figcaption className="blockquote-footer mb-0">
|
||||
{/* <div className="d-flex avatar avatar-xs">
|
||||
<span className="avatar-initial rounded-circle bg-label-primary">
|
||||
{report?.assignedBy?.firstName.slice(0, 1)}
|
||||
</span> */}
|
||||
<cite title="Source Title m-0">{` ${report?.assignedBy.firstName} ${report?.assignedBy.lastName}`}</cite>
|
||||
{/* </div> */}
|
||||
</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div className="d-flex p-0 m-0">
|
||||
<div className="flex-shrink-0 mt-1 mx-sm-0 px-2 mx-auto">
|
||||
<i class="bx bx-buildings"></i>
|
||||
</div>
|
||||
<p class="lead">{report?.workItem?.workArea?.floor?.building?.name}</p>
|
||||
<p class="lead ms-12">{report?.workItem?.workArea?.floor?.floorName}</p>
|
||||
</div>
|
||||
<dl class="row text-start ms-3">
|
||||
<dt class="col-sm-6">
|
||||
Work Area : {report?.workItem?.workArea?.areaName}
|
||||
</dt>
|
||||
<dd class="col-sm-6">
|
||||
<small> {report?.workItem?.activityMaster.activityName}</small>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="row text-start ms-3">
|
||||
<dt class="col-sm-4">Team</dt>
|
||||
|
||||
<dd class="col-sm-4 d-flex align-items-center avatar-group justify-content-start">
|
||||
{report?.teamMembers.map((member) => (
|
||||
<>
|
||||
<div
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-html="true"
|
||||
data-popup="tooltip-custom"
|
||||
data-bs-placement="top"
|
||||
title={`${member.firstName} ${member.lastName}`}
|
||||
className="avatar avatar-xs"
|
||||
>
|
||||
{/* <img src="..." alt="Avatar" class="rounded-circle pull-up" /> */}
|
||||
<span className="avatar-initial rounded-circle bg-label-primary">
|
||||
{member?.firstName.slice(0, 1)}
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
))}
|
||||
</dd>
|
||||
<dt class="col-sm-4 text-start">Planned : {report?.plannedTask}</dt>
|
||||
</dl>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="row p-0">
|
||||
<div className="col-4">
|
||||
<input
|
||||
{...register("completedTask", { valueAsNumber: true })}
|
||||
id="smallInput"
|
||||
className="form-control form-control-sm"
|
||||
type="number"
|
||||
placeholder="Completed Work"
|
||||
/>
|
||||
{errors.completedTask && (
|
||||
<div className="text-danger">{errors.completedTask.message}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="col-8">
|
||||
<textarea
|
||||
{...register("comment")}
|
||||
className="form-control"
|
||||
id="exampleFormControlTextarea1"
|
||||
rows="1"
|
||||
placeholder="Enter comment"
|
||||
/>
|
||||
{errors.comment && (
|
||||
<div className="text-danger">{errors.comment.message}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-12 text-center my-2">
|
||||
<button type="submit" className="btn btn-sm btn-primary me-3">
|
||||
{loading ? "Please wait":"Submit Report"}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-sm btn-label-secondary"
|
||||
onClick={handleClose}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
158
src/components/Activities/ReportTaskComments.jsx
Normal file
158
src/components/Activities/ReportTaskComments.jsx
Normal file
@ -0,0 +1,158 @@
|
||||
import React, {useEffect, useState} from "react";
|
||||
import {useProfile} from "../../hooks/useProfile";
|
||||
import moment from "moment";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
import {TasksRepository} from "../../repositories/TaskRepository";
|
||||
import showToast from "../../services/toastService";
|
||||
|
||||
|
||||
const schema = z.object({
|
||||
comment: z.string().min(1, "Comment cannot be empty"),
|
||||
});
|
||||
|
||||
const ReportTaskComments = ( {commentsData, closeModal} ) =>
|
||||
{
|
||||
const [loading,setloading]=useState(false)
|
||||
const {profile} = useProfile()
|
||||
const [comments,setComment] = useState([])
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
formState: { errors },reset
|
||||
} = useForm({
|
||||
resolver: zodResolver(schema),
|
||||
});
|
||||
|
||||
useEffect( () =>
|
||||
{
|
||||
setComment(commentsData?.comments
|
||||
)
|
||||
}, [commentsData] )
|
||||
const isLoggedUser = ( usrId ) => profile?.employeeInfo.id;
|
||||
|
||||
const onSubmit = async(data) =>
|
||||
{
|
||||
let sendComment = {
|
||||
...data,
|
||||
taskAllocationId: commentsData?.id,
|
||||
commentDate: new Date().toISOString(),
|
||||
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
setloading(true)
|
||||
// const resp = await TasksRepository.taskComments( sendComment );
|
||||
// console.timeLog( resp )
|
||||
reset()
|
||||
setloading(false)
|
||||
showToast( "Successfully Sent", "success" )
|
||||
closeModal()
|
||||
} catch ( err )
|
||||
{
|
||||
setloading(false)
|
||||
showToast(error.response.data?.message || "Something wrong","error")
|
||||
}
|
||||
|
||||
}
|
||||
return (
|
||||
<div
|
||||
className="modal-dialog modal-md modal-simple report-task-comments-modal"
|
||||
role="document"
|
||||
>
|
||||
<div className="modal-content">
|
||||
<div className="modal-body px-1">
|
||||
<button
|
||||
type="button"
|
||||
className="btn-close"
|
||||
onClick={closeModal}
|
||||
aria-label="Close"
|
||||
></button>
|
||||
<div className="container ">
|
||||
|
||||
{
|
||||
comments && comments.map( ( data ) =>
|
||||
(
|
||||
<div className="text-start" key={data.id}>
|
||||
<div class={`li-wrapper d-flex justify-content-${isLoggedUser(data?.employee?.id) ? "end":"start"} align-items-start`}>
|
||||
<div class="avatar avatar-xs me-1">
|
||||
<span class="avatar-initial rounded-circle bg-label-success">
|
||||
M
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-start py-0">
|
||||
<p class="mb-0">
|
||||
<strong>{ `${data?.employee?.firstName} ${data?.employee?.lastName}`}</strong>
|
||||
</p>
|
||||
<small style={{fontSize: "10px"}}>{ moment(data?.commentDate).fromNow()}</small>
|
||||
</div>
|
||||
</div>
|
||||
<p className={`ms-${ isLoggedUser( data?.employee?.id ) ? "0 text-end me-6" : "6 " } mt-1`}>{ data?.comment
|
||||
}</p>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
{/* by other users */}
|
||||
{/* <div className="text-start">
|
||||
<div class="li-wrapper d-flex justify-content-start align-items-start">
|
||||
<div class="avatar avatar-xs me-1">
|
||||
<span class="avatar-initial rounded-circle bg-label-success">
|
||||
M
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-start py-0">
|
||||
<p class="mb-0">
|
||||
<strong>Mahajan</strong>
|
||||
</p>
|
||||
<small style={{ fontSize: "10px" }}>2 hour ago</small>
|
||||
</div>
|
||||
</div>
|
||||
<p className="ms-6 mt-1">Stylized implementation of HTML’s element for abbreviations and acronyms to show the expanded version on hover. Abbreviations have a default underline and gain a help cursor to provide additional context on hov </p>
|
||||
</div> */}
|
||||
|
||||
{/* by login usrer */}
|
||||
{/* <div className="text-start">
|
||||
<div class="li-wrapper d-flex justify-content-end align-items-start">
|
||||
<div class="avatar avatar-xs me-1">
|
||||
<span class="avatar-initial rounded-circle bg-label-success">
|
||||
M
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-start py-0">
|
||||
<p class="mb-0">
|
||||
<strong>Pramod Mahajan</strong>
|
||||
</p>
|
||||
<small style={{ fontSize: "10px" }}>2 hour ago</small>
|
||||
</div>
|
||||
</div>
|
||||
<p className="ms-6 mt-1">Stylized implementation of HTML’s element for abbreviations and acronyms to show the expanded version on hover. Abbreviations have a default underline and gain a help cursor to provide additional context on hov </p>
|
||||
</div> */}
|
||||
<form onSubmit={handleSubmit( onSubmit )}>
|
||||
<textarea
|
||||
{...register("comment")}
|
||||
className="form-control"
|
||||
id="exampleFormControlTextarea1"
|
||||
rows="1"
|
||||
placeholder="Enter comment"
|
||||
/>
|
||||
{errors.comment && (
|
||||
<div className="danger-text">{errors.comment.message}</div>
|
||||
)}
|
||||
<div class="text-end my-1">
|
||||
|
||||
<button type="button" class="btn btn-secondary" onClick={closeModal} data-bs-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-primary ms-2">{ loading ? "Sending...":"Comment"}</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReportTaskComments;
|
@ -16,13 +16,12 @@ import showToast from "../../services/toastService";
|
||||
const schema = z.object({
|
||||
selectedEmployees: z.array( z.number() ).min( 1, {message: "At least one employee must be selected"} ),
|
||||
description: z.string().min( 1, {message: "description required"} ),
|
||||
pannedTask: z.number()
|
||||
.refine(value => value > 0, { message: "pannedTask should be greater than zero" })
|
||||
.refine(value => value !== undefined, { message: "pannedTask is required" }),
|
||||
|
||||
})
|
||||
|
||||
|
||||
const AssignRoleModel = ( {assignData,onClose}) => {
|
||||
const [ plannedTask, setPlannedTask ] = useState()
|
||||
const { openModal, closeModal } = useModal()
|
||||
const selectedProject = useSelector((store)=>store.localVariables.projectId)
|
||||
const {employees} = useEmployeesAllOrByProjectId( selectedProject )
|
||||
@ -78,7 +77,7 @@ const handleEmployeeSelection = (employeeId,field) => {
|
||||
const removeEmployee = (employeeId) => {
|
||||
setSelectedEmployees((prevSelected) => {
|
||||
const updatedSelection = prevSelected.filter((id) => id !== employeeId);
|
||||
setValue("selectedEmployees", updatedSelection);
|
||||
setValue("selectedEmployees", updatedSelection); // Ensure form state is updated
|
||||
return updatedSelection;
|
||||
});
|
||||
};
|
||||
@ -105,7 +104,6 @@ const onSubmit = async(data) => {
|
||||
}
|
||||
|
||||
};
|
||||
console.log(assignData?.workItem?.workItem)
|
||||
useEffect(()=>{
|
||||
dispatch(changeMaster("Job Role"))
|
||||
return ()=> setSelectedRole("all")
|
||||
@ -212,6 +210,8 @@ useEffect(()=>{
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
{selectedEmployees.length > 0 && (
|
||||
<div className="mt-1">
|
||||
<div className="text-start px-2">
|
||||
@ -236,28 +236,22 @@ useEffect(()=>{
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{errors.selectedEmployees && (
|
||||
<div className="danger-text mt-1">
|
||||
<p>{errors.selectedEmployees[0]}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div class="col-md text-start mx-0 px-0">
|
||||
<div class="form-check form-check-inline mt-4 px-1">
|
||||
<label className="form-text fs-6" for="inlineCheckbox1">Pending Work</label>
|
||||
<label className="form-check-label ms-2" for="inlineCheckbox1">{ assignData?.workItem?.workItem?.plannedWork - assignData?.workItem?.workItem?.completedWork}</label>
|
||||
</div>
|
||||
<div className="form-check form-check-inline col-sm-2 col">
|
||||
<label for="defaultFormControlInput" className="form-label">Target</label>
|
||||
<Controller name="pannedTask" control={control} render={( {field} ) => (
|
||||
<input type="text" className="form-control form-control-sm " {...field} />
|
||||
)} />
|
||||
{errors.pannedTask && (
|
||||
<div className="danger-text">
|
||||
<p>{errors.pannedTask.message}</p>
|
||||
</div>
|
||||
)}
|
||||
<label for="defaultFormControlInput" className="form-label">Target</label>
|
||||
<input type="text" className="form-control form-control-sm " value={plannedTask} onChange={(e)=>setPlannedTask(e.target.value)} id="defaultFormControlInput" aria-describedby="defaultFormControlHelp" />
|
||||
</div>
|
||||
</div>
|
||||
{errors.selectedEmployees && (
|
||||
<div className="danger-text mt-1">
|
||||
<p>{errors.selectedEmployees[0]}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<label for="exampleFormControlTextarea1" className="form-label">Description</label>
|
||||
<Controller
|
||||
|
@ -16,6 +16,7 @@ const buildingSchema = z.object({
|
||||
|
||||
const BuildingModel = ({
|
||||
project,
|
||||
onClose,
|
||||
onSubmit,
|
||||
clearTrigger,
|
||||
onClearComplete,
|
||||
@ -70,6 +71,8 @@ const BuildingModel = ({
|
||||
className="btn-close"
|
||||
data-bs-dismiss="modal"
|
||||
aria-label="Close"
|
||||
onClick={onClose}
|
||||
|
||||
></button>
|
||||
<h5 className="text-center mb-2">Manage Buildings - {project.name}</h5>
|
||||
<form onSubmit={handleSubmit(onSubmitHandler)} className="row g-2">
|
||||
@ -115,7 +118,7 @@ const BuildingModel = ({
|
||||
<button type="submit" className="btn btn-primary me-3">
|
||||
{formData.id ? "Edit Building" : "Add Building"}
|
||||
</button>
|
||||
<button type="reset" className="btn btn-label-secondary" data-bs-dismiss="modal" aria-label="Close">
|
||||
<button type="reset" className="btn btn-label-secondary" data-bs-dismiss="modal" aria-label="Close" onClick={onClose}>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
|
@ -2,11 +2,16 @@ import React, { useState } from "react";
|
||||
import { useModal } from "../../../ModalContext";
|
||||
import AssignRoleModel from "../AssignRole";
|
||||
import {useParams} from "react-router-dom";
|
||||
import GlobalModel from "../../common/GlobalModel";
|
||||
|
||||
const WorkItem = ( {workItem, forBuilding, forFloor, forWorkArea} ) =>{
|
||||
const {projectId} = useParams()
|
||||
const { openModal ,closedModal} = useModal();
|
||||
const [itemName, setItemName] = useState('');
|
||||
const [ itemName, setItemName ] = useState( '' );
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
|
||||
|
||||
const openModal = () => setIsModalOpen(true);
|
||||
const closeModal = () => setIsModalOpen(false);
|
||||
const getProgress = (planned, completed) => {
|
||||
return (completed * 100) / planned + "%";
|
||||
};
|
||||
@ -16,12 +21,12 @@ const WorkItem = ( {workItem, forBuilding, forFloor, forWorkArea} ) =>{
|
||||
setItemName('');
|
||||
};
|
||||
|
||||
const showCreateItemModal = (modalData) => {
|
||||
openModal(
|
||||
<AssignRoleModel assignData={modalData} onClose={closedModal} />,
|
||||
handleAssignTask ,"lg"
|
||||
);
|
||||
};
|
||||
// const showCreateItemModal = (modalData) => {
|
||||
// openModal(
|
||||
// <AssignRoleModel assignData={modalData} onClose={closedModal} />,
|
||||
// handleAssignTask ,"lg"
|
||||
// );
|
||||
// };
|
||||
|
||||
let assigndata = {
|
||||
building: forBuilding,
|
||||
@ -30,6 +35,11 @@ const WorkItem = ( {workItem, forBuilding, forFloor, forWorkArea} ) =>{
|
||||
workItem
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<GlobalModel isOpen={isModalOpen}
|
||||
closeModal={closeModal} dialogClass="modal-dialog-centered" role="document" size="lg" >
|
||||
<AssignRoleModel assignData={assigndata} onClose={closeModal} />
|
||||
</GlobalModel>
|
||||
<tr>
|
||||
<td className="text-start table-cell-small">
|
||||
<i className="bx bx-right-arrow-alt"></i>
|
||||
@ -68,10 +78,7 @@ const WorkItem = ( {workItem, forBuilding, forFloor, forWorkArea} ) =>{
|
||||
className="btn p-0"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#project-modal"
|
||||
onClick={() =>
|
||||
{
|
||||
showCreateItemModal(assigndata)
|
||||
}}
|
||||
onClick={openModal}
|
||||
>
|
||||
<span className="badge bg-label-primary me-1">Assign</span>
|
||||
</button>)}
|
||||
@ -91,7 +98,8 @@ const WorkItem = ( {workItem, forBuilding, forFloor, forWorkArea} ) =>{
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tr>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -5,12 +5,14 @@ import ProjectRepository from "../../repositories/ProjectRepository";
|
||||
import { cacheData,getCachedData } from "../../slices/apiDataManager";
|
||||
import {hasUserPermission} from "../../utils/authUtils";
|
||||
import moment from "moment";
|
||||
import {useHasUserPermission} from "../../hooks/useHasUserPermission";
|
||||
import {MANAGE_PROJECT} from "../../utils/constants";
|
||||
|
||||
|
||||
const ProjectBanner = ( {project_data} ) =>
|
||||
{
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
|
||||
const manageProject = useHasUserPermission(MANAGE_PROJECT)
|
||||
const [ CurrentProject, setCurrentProject ] = useState( project_data )
|
||||
if (project_data == null) {
|
||||
return <span>incomplete project information</span>;
|
||||
@ -118,7 +120,7 @@ const ProjectBanner = ( {project_data} ) =>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className={`btn btn-sm btn-primary ${hasUserPermission("53176ebf-c75d-42e5-839f-4508ffac3def") ? "":"d-none"}`}
|
||||
className={`btn btn-sm btn-primary ${!manageProject && 'd-none'}`}
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#edit-project-modal"
|
||||
onClick={handleShow}
|
||||
|
@ -223,6 +223,7 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
|
||||
const closeBuildingModel = () => {
|
||||
setIsBuildingModalOpen(false);
|
||||
};
|
||||
|
||||
const handleBuildingModelFormSubmit = (buildingmodel) => {
|
||||
if (buildingmodel.id == "" || buildingmodel.id == 0)
|
||||
delete buildingmodel.id;
|
||||
@ -337,7 +338,6 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
<div
|
||||
className={`modal fade ${showModal ? 'show' : ''}`}
|
||||
tabIndex="-1"
|
||||
@ -347,14 +347,12 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
|
||||
>
|
||||
<BuildingModel
|
||||
project={data}
|
||||
onClose={closeBuildingModel}
|
||||
onClose={handleClose}
|
||||
onSubmit={handleBuildingModelFormSubmit}
|
||||
clearTrigger={clearFormTrigger}
|
||||
onClearComplete={() => setClearFormTrigger(false)}
|
||||
></BuildingModel>
|
||||
</div>
|
||||
|
||||
|
||||
{isFloorModalOpen && (
|
||||
<div
|
||||
className={`modal fade `}
|
||||
|
77
src/components/common/GlobalModel.jsx
Normal file
77
src/components/common/GlobalModel.jsx
Normal file
@ -0,0 +1,77 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
|
||||
const GlobalModel = ({
|
||||
isOpen,
|
||||
closeModal,
|
||||
children,
|
||||
modalType = '', // For custom positioning like modal-top, modal-bottom
|
||||
dialogClass = '', // For additional custom classes on modal dialog
|
||||
role = 'dialog', // Accessibility role for the modal
|
||||
size = '', // Dynamically set the size (sm, lg, xl)
|
||||
dataAttributes = {} // Additional dynamic data-bs-* attributes
|
||||
}) => {
|
||||
const modalRef = useRef(null); // Reference to the modal element
|
||||
|
||||
useEffect(() => {
|
||||
const modalElement = modalRef.current;
|
||||
const modalInstance = new window.bootstrap.Modal(modalElement);
|
||||
|
||||
// Show modal if isOpen is true
|
||||
if (isOpen) {
|
||||
modalInstance.show();
|
||||
} else {
|
||||
modalInstance.hide();
|
||||
}
|
||||
|
||||
// Handle modal hide event to invoke the closeModal function
|
||||
const handleHideModal = () => {
|
||||
closeModal(); // Close the modal via React state
|
||||
};
|
||||
|
||||
modalElement.addEventListener('hidden.bs.modal', handleHideModal);
|
||||
|
||||
return () => {
|
||||
modalElement.removeEventListener('hidden.bs.modal', handleHideModal);
|
||||
};
|
||||
}, [isOpen, closeModal]);
|
||||
|
||||
// Dynamically set the modal size classes (modal-sm, modal-lg, modal-xl)
|
||||
const modalSizeClass = size ? `modal-${size}` : ''; // Default is empty if no size is specified
|
||||
|
||||
// Dynamically generate data-bs attributes
|
||||
const dataAttributesProps = Object.keys(dataAttributes).map(key => ({
|
||||
[key]: dataAttributes[key],
|
||||
}));
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`modal fade ${modalType}`}
|
||||
id="customModal"
|
||||
tabIndex="-1"
|
||||
aria-labelledby="exampleModalLabel"
|
||||
aria-hidden="true"
|
||||
ref={modalRef} // Assign the ref to the modal element
|
||||
{...dataAttributesProps}
|
||||
>
|
||||
<div className={`modal-dialog ${dialogClass} ${modalSizeClass}`} role={role}>
|
||||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
{/* Close button inside the modal header */}
|
||||
<button
|
||||
type="button"
|
||||
className="btn-close"
|
||||
data-bs-dismiss="modal"
|
||||
aria-label="Close"
|
||||
onClick={closeModal} // Trigger the React closeModal function
|
||||
></button>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
{children} {/* Render children here, which can be the ReportTask component */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default GlobalModel;
|
40
src/hooks/useTasks.js
Normal file
40
src/hooks/useTasks.js
Normal file
@ -0,0 +1,40 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { TasksRepository } from "../repositories/TaskRepository";
|
||||
import { cacheData, getCachedData } from "../slices/apiDataManager";
|
||||
|
||||
export const useTaskList = (projectId, fromDate, ToDate) => {
|
||||
const [TaskList, setTaskList] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState(null);
|
||||
|
||||
const fetchList = async () => {
|
||||
const taskList_cached = getCachedData("taskList");
|
||||
if (!taskList_cached || taskList_cached?.projectId !== projectId) {
|
||||
try {
|
||||
setLoading(true);
|
||||
const resp = await TasksRepository.getTaskList(
|
||||
projectId,
|
||||
fromDate,
|
||||
ToDate
|
||||
);
|
||||
setTaskList(resp.data);
|
||||
cacheData("taskList", { projectId: projectId, data: resp.data });
|
||||
setLoading(false);
|
||||
} catch (err) {
|
||||
setLoading(false);
|
||||
console.log(err);
|
||||
setError(err);
|
||||
}
|
||||
} else {
|
||||
setTaskList(taskList_cached.data);
|
||||
}
|
||||
};
|
||||
console.log(TaskList)
|
||||
useEffect(() => {
|
||||
if (projectId) {
|
||||
fetchList();
|
||||
}
|
||||
}, [projectId, fromDate, ToDate]);
|
||||
|
||||
return { TaskList, loading, error, refetch:fetchList};
|
||||
};
|
@ -1,10 +1,81 @@
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import Breadcrumb from "../../components/common/Breadcrumb";
|
||||
import { dailyTask } from "../../data/masters";
|
||||
import { useTaskList } from "../../hooks/useTasks";
|
||||
import { useProjects } from "../../hooks/useProjects";
|
||||
import { setProjectId } from "../../slices/localVariablesSlice";
|
||||
import { useProfile } from "../../hooks/useProfile";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import {formatDate} from "../../utils/dateUtils";
|
||||
import GlobalModel from "../../components/common/GlobalModel";
|
||||
import AssignRoleModel from "../../components/Project/AssignRole";
|
||||
import {ReportTask} from "../../components/Activities/ReportTask";
|
||||
import ReportTaskComments from "../../components/Activities/ReportTaskComments";
|
||||
|
||||
import Breadcrumb from "../../components/common/Breadcrumb"
|
||||
import { dailyTask } from "../../data/masters"
|
||||
const DailyTask =()=>{
|
||||
return (
|
||||
<>
|
||||
<div className="container-xxl flex-grow-1 container-p-y">
|
||||
const DailyTask = () => {
|
||||
const { profile: LoggedUser } = useProfile();
|
||||
const {
|
||||
projects,
|
||||
loading: project_lodaing,
|
||||
error: projects_Error,
|
||||
} = useProjects();
|
||||
const selectedProject = useSelector(
|
||||
(store) => store.localVariables.projectId
|
||||
);
|
||||
const dispatch = useDispatch( selectedProject );
|
||||
const {
|
||||
TaskList,
|
||||
loading: task_loading,
|
||||
error: task_error,
|
||||
refetch
|
||||
} = useTaskList(selectedProject);
|
||||
const [TaskLists, setTaskLists] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
setTaskLists(TaskList);
|
||||
}, [ TaskList, selectedProject ] );
|
||||
|
||||
const [ selectedTask, selectTask ] = useState( null )
|
||||
const [comments,setComment] = useState(null)
|
||||
|
||||
const [ isModalOpen, setIsModalOpen ] = useState( false );
|
||||
const [ isModalOpenComment, setIsModalOpenComment ] = useState( false )
|
||||
|
||||
const openModal = () => setIsModalOpen(true);
|
||||
const closeModal = () => setIsModalOpen( false );
|
||||
|
||||
const openComment = () =>setIsModalOpenComment(true)
|
||||
const closeCommentModal =()=>setIsModalOpenComment(false)
|
||||
const handletask = (task) =>
|
||||
{
|
||||
selectTask(task)
|
||||
openModal()
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={`modal fade ${isModalOpen ? 'show' : ''}`}
|
||||
tabIndex="-1"
|
||||
role="dialog"
|
||||
style={{ display: isModalOpen ? 'block' : 'none' }}
|
||||
aria-hidden={!isModalOpen}
|
||||
>
|
||||
<ReportTask report={selectedTask} closeModal={ closeModal} refetch={refetch} />
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={`modal fade ${isModalOpenComment ? 'show' : ''}`}
|
||||
tabIndex="-1"
|
||||
role="dialog"
|
||||
style={{ display: isModalOpenComment ? 'block' : 'none' }}
|
||||
aria-hidden={!isModalOpenComment}
|
||||
>
|
||||
<ReportTaskComments commentsData={comments} closeModal={ closeCommentModal} />
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div className="container-xxl flex-grow-1 container-p-y">
|
||||
<Breadcrumb
|
||||
data={[
|
||||
{ label: "Home", link: "/dashboard" },
|
||||
@ -14,61 +85,153 @@ const DailyTask =()=>{
|
||||
<div className="card card-action mb-6">
|
||||
<div className="card-body">
|
||||
<div className="row">
|
||||
<div className="col-sm-3 col-8 text-start mb-1">
|
||||
<select
|
||||
name="DataTables_Table_0_length"
|
||||
aria-controls="DataTables_Table_0"
|
||||
className="form-select form-select-sm"
|
||||
value={selectedProject}
|
||||
onChange={(e) => dispatch(setProjectId(e.target.value))}
|
||||
aria-label=""
|
||||
>
|
||||
{(project_lodaing || projects.length < 0) && (
|
||||
<option value="Loading..." disabled>
|
||||
Loading...
|
||||
</option>
|
||||
)}
|
||||
{!project_lodaing &&
|
||||
projects
|
||||
?.filter((project) =>
|
||||
LoggedUser?.projects?.map(Number).includes(project.id)
|
||||
)
|
||||
.map((project) => (
|
||||
<option value={project.id} key={project.id}>
|
||||
{project.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="table-responsive text-nowrap">
|
||||
{/* {employees && employees.length > 0 ? ( */}
|
||||
<table className="table ">
|
||||
<thead>
|
||||
<table className="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Activity</th>
|
||||
<th>Planned </th>
|
||||
<th>Compeleted</th>
|
||||
<th>Assign On</th>
|
||||
<th>Team</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="table-border-bottom-0">
|
||||
{TaskLists?.length === 0 && !task_loading && (
|
||||
<tr>
|
||||
<th>Sr</th>
|
||||
<th>Project Name</th>
|
||||
<th>Target</th>
|
||||
<th>Employees</th>
|
||||
|
||||
|
||||
<th>Actions</th>
|
||||
<td colSpan={7} className="text-center">
|
||||
No Data Found
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="table-border-bottom-0">
|
||||
)}
|
||||
|
||||
{task_loading && (
|
||||
<tr>
|
||||
<td colSpan={7} className="text-center">
|
||||
<p>Loading..</p>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
|
||||
{TaskLists.map((task, index) => {
|
||||
const accordionId = `accordion-${index}`;
|
||||
return (
|
||||
<React.Fragment key={index}>
|
||||
{/* Main Row */}
|
||||
<tr >
|
||||
<td>
|
||||
<div className="d-flex justify-content-center align-items-center">
|
||||
|
||||
<div className="d-flex justify-content-center align-items-center" data-bs-toggle="collapse"
|
||||
data-bs-target={`#${accordionId}`}
|
||||
aria-expanded="false"
|
||||
aria-controls={accordionId}
|
||||
>
|
||||
<div className="d-flex flex-column">
|
||||
<a href="#" className="text-heading text-truncate">
|
||||
<span className="fw-medium ">
|
||||
1
|
||||
</span>
|
||||
<a
|
||||
href="#"
|
||||
className="text-heading text-truncate"
|
||||
|
||||
>
|
||||
<i class='bx bx-chevron-right'></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="flex-wrap">
|
||||
project Name project Name project Name
|
||||
{task.workItem.activityMaster.activityName || "No Activity Name"}
|
||||
</td>
|
||||
<td>{task.plannedTask || "NA"}</td>
|
||||
<td>{task.completedTask}</td>
|
||||
<td>{formatDate( task.assignmentDate )}</td>
|
||||
<td className="text-center">
|
||||
<div class="d-flex align-items-center avatar-group justify-content-center">
|
||||
{task.teamMembers.map( ( member ) => (
|
||||
|
||||
<td>
|
||||
80
|
||||
<div key={member.id} data-bs-toggle="tooltip" data-bs-html="true" data-popup="tooltip-custom" data-bs-placement="top" title={`${member.firstName} ${member.lastName}`} className="avatar avatar-xs">
|
||||
{/* <img src="..." alt="Avatar" class="rounded-circle pull-up" /> */}
|
||||
<span className="avatar-initial rounded-circle bg-label-primary">{member?.firstName.slice(0,1) }</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td> NA</td>
|
||||
|
||||
<td>
|
||||
|
||||
<button type="button" className="btn btn-xs btn-primary">Report</button>
|
||||
<td className="text-center">
|
||||
<div className="d-flex justify-content-center">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-xs btn-primary"
|
||||
onClick={() =>
|
||||
{
|
||||
selectTask( task )
|
||||
openModal()
|
||||
}}
|
||||
>
|
||||
Report
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-xs btn-primary ms-2"
|
||||
onClick={() =>
|
||||
{
|
||||
setComment( task )
|
||||
openComment()
|
||||
}}
|
||||
>
|
||||
Comment
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
{/* ))} */}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{/* Accordion Content */}
|
||||
<tr
|
||||
id={accordionId}
|
||||
className="accordion-collapse collapse"
|
||||
>
|
||||
<td colSpan={5}>
|
||||
<div className="row">
|
||||
<p>{task.subdata?.name}</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default DailyTask
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default DailyTask;
|
||||
|
@ -17,7 +17,8 @@ const loginScheam = z.object( {
|
||||
|
||||
const LoginPage = () => {
|
||||
const navigate = useNavigate();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [ loading, setLoading ] = useState( false );
|
||||
const[hidepass,setHidepass] = useState(true)
|
||||
|
||||
const {register,
|
||||
handleSubmit,
|
||||
@ -93,7 +94,7 @@ const LoginPage = () => {
|
||||
</div>
|
||||
<div className="input-group input-group-merge">
|
||||
<input
|
||||
type="password"
|
||||
type={hidepass ? "password" :"text"}
|
||||
autoComplete="true"
|
||||
id="password"
|
||||
{...register("password")}
|
||||
@ -102,7 +103,7 @@ const LoginPage = () => {
|
||||
placeholder="············"
|
||||
aria-describedby="password"
|
||||
/>
|
||||
<span className="input-group-text cursor-pointer"></span>
|
||||
<span class="input-group-text cursor-pointer" onClick={()=>setHidepass(!hidepass)}>{ hidepass ? <i className="bx bx-hide"></i> :<i className="bx bx-show"></i>}</span>
|
||||
</div>
|
||||
{errors.password && (
|
||||
<div
|
||||
|
7
src/repositories/TaskRepository.jsx
Normal file
7
src/repositories/TaskRepository.jsx
Normal file
@ -0,0 +1,7 @@
|
||||
import {api} from "../utils/axiosClient";
|
||||
|
||||
export const TasksRepository = {
|
||||
getTaskList: ( id, fromdate = null, todate = null ) => api.get( `api/task/list?projectId=${ id }` ),
|
||||
reportTsak: ( data ) => api.post( 'api/task/report', data ),
|
||||
taskComments:(data)=>api.post("api/task/comment",data)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user