Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test PR #336

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions api/NotificationDataClasses/OvertimeData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ public class OvertimeData
public string Type { get; set; } = default!;
public string Status { get; set; } = default!;
public string? Remarks { get; set; } = default!;

public bool? IsManagerApproved { get; set; }
public bool? IsLeaderApproved { get; set; }

public string? OvertimeId { get; set; }
}

public class OvertimeManagerData : OvertimeData
Expand Down
5 changes: 5 additions & 0 deletions api/Schema/Queries/OvertimeQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ public OvertimeQuery(OvertimeService overtimeService)
return await _overtimeService.GetOvertime(UserId);
}

public async Task<DTOs.MyOvertimeDTO?> GetOvertimeById(int id)
{
return await _overtimeService.GetOvertimeById(id);
}

public async Task<List<DTOs.OvertimeDTO>> GetAllOvertime()
{
return await _overtimeService.Index();
Expand Down
200 changes: 116 additions & 84 deletions api/Services/ApprovalService.cs

Large diffs are not rendered by default.

54 changes: 44 additions & 10 deletions api/Services/NotificationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,10 @@ public async Task<List<OvertimeNotification>> createOvertimeNotification(Overtim
DateFiled = (DateTime)overtime.CreatedAt!,
Type = NotificationDataTypeEnum.REQUEST,
Status = _overtimeService.GetOvertimeRequestStatus(overtime),
Remarks = overtime.Remarks
Remarks = overtime.Remarks,
IsLeaderApproved = overtime.IsLeaderApproved,
IsManagerApproved = overtime.IsManagerApproved,
OvertimeId = overtime.Id.ToString()
}
);

Expand Down Expand Up @@ -175,7 +178,11 @@ public async Task<List<OvertimeNotification>> createOvertimeNotification(Overtim
DateFiled = (DateTime)overtime.CreatedAt,
Type = NotificationDataTypeEnum.REQUEST,
Status = _overtimeService.GetOvertimeRequestStatus(overtime),
Remarks = overtime.Remarks
Remarks = overtime.Remarks,
IsLeaderApproved = overtime.IsLeaderApproved,
IsManagerApproved = overtime.IsManagerApproved,
OvertimeId = overtime.Id.ToString()
// TODO: create the part when either the manager/leader disapproves, it will update so that the other can't update
}
);

Expand Down Expand Up @@ -561,33 +568,60 @@ public async Task<LeaveNotification> createLeaveApproveDisapproveNotification(Le
}
}

public async Task<OvertimeNotification> createOvertimeApproveDisapproveNotification(Overtime overtime, int fromUserId, bool IsApproved)
public async Task<OvertimeNotification> CreateOvertimeApproveDisapproveNotification(Overtime overtime, int fromUserId, bool IsApproved)
{
using (HrisContext context = _contextFactory.CreateDbContext())
{
//for time entries
var timeEntry = context.TimeEntries.Find(overtime.TimeEntryId);
//from the time entry, get the time in and time out
var timeInEntry = timeEntry?.EndTime + TimeSpan.FromHours(1);
var timeOutEntry = context.Times.Find(timeEntry?.TimeOutId);

var timeIn = timeInEntry?.ToString(@"hh\:mm");
var timeOut = timeOutEntry?.TimeHour.ToString(@"hh\:mm");

var managerStatus = overtime.IsManagerApproved switch
{
true => RequestStatus.APPROVED,
false => RequestStatus.DISAPPROVED,
null => RequestStatus.PENDING // if IsManagerApproved is nullable
};

var leaderStatus = overtime.IsLeaderApproved switch
{
true => RequestStatus.APPROVED,
false => RequestStatus.DISAPPROVED,
null => RequestStatus.PENDING // if IsLeaderApproved is nullable
};

var user = context.Users.Find(fromUserId);
var projectNames = context.MultiProjects.Where(x => x.OvertimeId == overtime.Id && x.Type == MultiProjectTypeEnum.OVERTIME).Select(x => x.ProjectId == ProjectId.OTHER_PROJECT ? overtime.OtherProject : x.Project.Name);
var dataToUser = JsonSerializer.Serialize(new
{
User = new
{
Id = user?.Id,
Id = user?.Id, // Explicitly naming the properties
Name = user?.Name,
AvatarLink = _userService.GenerateAvatarLink(user?.ProfileImageId ?? default(int))
},
Projects = projectNames,
RequestedMinutes = overtime.RequestedMinutes,
Projects = projectNames, // This one is fine because it's already a named property
RequestedMinutes = overtime.RequestedMinutes, // Explicitly naming the properties
DateRequested = overtime.OvertimeDate,
ApprovedMinutes = overtime.ApprovedMinutes,
DateFiled = overtime.CreatedAt,
Type = IsApproved ? NotificationDataTypeEnum.APPROVE : NotificationDataTypeEnum.DISAPPROVE,
Status = IsApproved ? RequestStatus.APPROVED : RequestStatus.DISAPPROVED,
Remarks = overtime.Remarks,
ManagerRemarks = overtime.ManagerRemarks,
RequestedTimeIn = overtime.TimeEntry.TimeIn!.TimeHour.ToString(@"hh\:mm"),
RequestedTimeOut = overtime.TimeEntry.TimeOut!.TimeHour.ToString(@"hh\:mm")
}
);
RequestedTimeIn = timeIn,
RequestedTimeOut = timeOut,
Duration = overtime.RequestedMinutes,
ManagerApproveStatus = managerStatus,
LeaderApproveStatus = leaderStatus,

});


// Notification to Requesting User
var notificationToUser = new OvertimeNotification
Expand Down
20 changes: 20 additions & 0 deletions api/Services/OvertimeService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,26 @@ public async Task<List<MyOvertimeDTO>> GetOvertime(int UserId)
.ToListAsync();
}
}

public async Task<MyOvertimeDTO?> GetOvertimeById(int id)
{
using (HrisContext context = _contextFactory.CreateDbContext())
{
// Find the Overtime entity by ID and return a single DTO object
return await context.Overtimes
.Include(x => x.MultiProjects)
.ThenInclude(x => x.Project)
.Include(x => x.MultiProjects)
.ThenInclude(x => x.ProjectLeader)
.Include(x => x.Manager)
.ThenInclude(x => x.Role)
.Where(w => w.Id == id)
.OrderByDescending(x => x.CreatedAt)
.Select(x => new MyOvertimeDTO(x))
.SingleOrDefaultAsync(); // Use SingleOrDefaultAsync to return a single MyOvertimeDTO or null
}
}

public async Task<List<OvertimeDTO>> Index()
{
var domain = _httpService.getDomainURL();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,34 @@
import moment from 'moment'
import React, { FC } from 'react'
import React, { FC, useEffect, useState } from 'react'

import { INotification } from '~/utils/interfaces'
import RequestStatusChip from '~/components/atoms/RequestStatusChip'
import { useGetOvertimeById } from '~/hooks/useOvertimeQuery'

type Props = {
notification: INotification
}

const OvertimeDetails: FC<Props> = ({ notification }): JSX.Element => {
const { project, date, duration, dateFiled, status, remarks } = notification
const { project, date, duration, dateFiled, remarks } = notification

const [overtimeId, setOvertimeId] = useState<number | null>(null) // Ensure the type is clear and initialized correctly
useEffect(() => {
if (notification.overtimeId !== undefined) {
setOvertimeId(parseInt(notification.overtimeId))
}
}, [notification.overtimeId])

const { data } = useGetOvertimeById(overtimeId ?? 0) // Fallback to 0 if overtimeId is null

const overtime = data?.overtimeById

let managerApprovalState = 'Pending'
if (overtime?.isManagerApproved === true) {
managerApprovalState = 'Approved'
} else if (overtime?.isManagerApproved === false) {
managerApprovalState = 'Disapproved'
}

return (
<>
Expand All @@ -32,9 +51,13 @@ const OvertimeDetails: FC<Props> = ({ notification }): JSX.Element => {
{moment(new Date(dateFiled)).fromNow()}
</span>
</li>
<li className="inline-flex items-center space-x-3 pt-2">
{/* <li className="inline-flex items-center space-x-3 pt-2">
<span className="text-slate-600">Status: </span>
<RequestStatusChip label={status.toLocaleLowerCase()} />
</li> */}
<li className="inline-flex items-center space-x-3 pt-2">
<span className="text-slate-600">Manager Status: </span>
<RequestStatusChip label={managerApprovalState.toLocaleLowerCase()} />
</li>
<li className="inline-flex flex-col space-y-2 pt-2">
<span className="text-slate-600">Remarks: </span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,27 @@ type Props = {
const OvertimeResolvedDetails: FC<Props> = ({ notification }): JSX.Element => {
const {
date,
status,
project,
remarks,
duration,
dateFiled,
managerRemarks,
requestedTimeIn,
requestedTimeOut
requestedTimeOut,
managerApproveStatus,
leaderApproveStatus
} = notification

let manager = ''
if (managerApproveStatus != null) {
manager = managerApproveStatus.toLowerCase()
}

let leader = ''
if (leaderApproveStatus != null) {
leader = leaderApproveStatus.toLowerCase()
}

return (
<>
<li className="inline-flex items-center space-x-3">
Expand All @@ -33,7 +44,9 @@ const OvertimeResolvedDetails: FC<Props> = ({ notification }): JSX.Element => {
</li>
<li className="inline-flex items-center space-x-3 pt-2">
<span className="text-slate-600">Duration: </span>
<span className="flex items-center font-medium">{duration}</span>
<span className="flex items-center font-medium">
{duration !== null && duration !== undefined ? `${duration} mins` : '---'}
</span>
</li>
<li className="inline-flex items-center space-x-3 pt-2">
<span className="text-slate-600">Time In: </span>
Expand All @@ -51,11 +64,15 @@ const OvertimeResolvedDetails: FC<Props> = ({ notification }): JSX.Element => {
</span>
</li>
<li className="inline-flex items-center space-x-3 pt-2">
<span className="text-slate-600">Status: </span>
<RequestStatusChip label={status.toLocaleLowerCase()} />
<span className="text-slate-600">Leader Status: </span>
<RequestStatusChip label={leader + ''} />
</li>
<li className="inline-flex items-center space-x-3 pt-2">
<span className="text-slate-600">Manager Status: </span>
<RequestStatusChip label={manager + ''} />
</li>
<li className="inline-flex flex-col space-y-2 pt-2">
<span className="text-slate-600">Manager Remarks: </span>
<span className="text-slate-600">Manager&apos;s Remarks: </span>
<span className="font-medium">{managerRemarks}</span>
</li>
<li className="inline-flex flex-col space-y-2 pt-2">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { FC } from 'react'
import React, { FC, useEffect, useState } from 'react'
import { useRouter } from 'next/router'
import { BsFileEarmarkText } from 'react-icons/bs'
import { ThumbsDown, ThumbsUp } from 'react-feather'
Expand Down Expand Up @@ -29,6 +29,7 @@ import { STATUS_OPTIONS } from '~/utils/constants/notificationFilter'
import { NOTIFICATION_TYPE } from '~/utils/constants/notificationTypes'
import ModalHeader from '~/components/templates/ModalTemplate/ModalHeader'
import ModalFooter from '~/components/templates/ModalTemplate/ModalFooter'
import { useGetOvertimeById } from '~/hooks/useOvertimeQuery'

type Props = {
isOpen: boolean
Expand Down Expand Up @@ -61,6 +62,15 @@ const ViewDetailsModal: FC<Props> = ({ isOpen, row, user }): JSX.Element => {
})
}

const [overtimeId, setOvertimeId] = useState(0)
useEffect(() => {
if (row.overtimeId !== undefined) {
setOvertimeId(parseInt(row.overtimeId))
}
}, [])

const { data } = useGetOvertimeById(overtimeId)

const handleApproveDisapprove = (isApproved: boolean): void => {
if (row.type.toLowerCase() === NOTIFICATION_TYPE.LEAVE) {
approveDisapproveLeaveMutation.mutate(
Expand Down Expand Up @@ -284,24 +294,26 @@ const ViewDetailsModal: FC<Props> = ({ isOpen, row, user }): JSX.Element => {
<span>View In Overtime Management</span>
</Button>
) : (
<>
<Button
variant="success"
className="flex items-center space-x-1.5 py-0.5 px-4"
onClick={() => handleApproveDisapprove(true)}
>
<ThumbsUp className="h-4 w-4" />
<span>Approve</span>
</Button>
<Button
variant="danger-outline"
className="flex items-center space-x-1.5 py-0.5 px-2"
onClick={() => handleApproveDisapprove(false)}
>
<ThumbsDown className="h-4 w-4" />
<span>Disapprove</span>
</Button>
</>
data?.overtimeById?.isManagerApproved !== false && (
<>
<Button
variant="success"
className="flex items-center space-x-1.5 py-0.5 px-4"
onClick={() => handleApproveDisapprove(true)}
>
<ThumbsUp className="h-4 w-4" />
<span>Approve</span>
</Button>
<Button
variant="danger-outline"
className="flex items-center space-x-1.5 py-0.5 px-2"
onClick={() => handleApproveDisapprove(false)}
>
<ThumbsDown className="h-4 w-4" />
<span>Disapprove</span>
</Button>
</>
)
)}
</ModalFooter>
)}
Expand Down
36 changes: 36 additions & 0 deletions client/src/graphql/queries/overtimeQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,39 @@ export const GET_ALL_OVERTIME = gql`
}
}
`

export const GET_OVERTIME_BY_ID = gql`
query GetOvertimeById($id: Int!) {
overtimeById(id: $id) {
id
projects {
id
project {
id
name
}
projectLeader {
id
name
}
}
otherProject
manager {
id
name
role {
id
name
}
}
supervisor
dateFiled
remarks
overtimeDate
requestedMinutes
approvedMinutes
isLeaderApproved
isManagerApproved
}
}
`
14 changes: 14 additions & 0 deletions client/src/hooks/useOvertimeQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { useQuery, UseQueryResult } from '@tanstack/react-query'
import { client } from '~/utils/shared/client'
import { IMyOvertimeData } from '~/utils/interfaces'
import { GET_ALL_OVERTIME_QUERY } from '~/graphql/queries/overtimeQueries'
import { MyOvertimeDTO } from '../../../api_v2/src/graphql/graphql'
import { GET_OVERTIME_BY_ID } from '~/graphql/queries/overtimeQuery'

export const getOvertimeQuery = (
userId: number
Expand All @@ -15,3 +17,15 @@ export const getOvertimeQuery = (
})
return result
}

export const useGetOvertimeById = (
id: number
): UseQueryResult<{ overtimeById: MyOvertimeDTO }, unknown> => {
const result = useQuery({
queryKey: ['GET_OVERTIME_BY_ID', id],
queryFn: async () => await client.request(GET_OVERTIME_BY_ID, { id }),
select: (data: { overtimeById: MyOvertimeDTO }) => data
})

return result
}
Loading
Loading