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

Feat billable hours #93

Draft
wants to merge 24 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f9bfe9a
fix: add missing migration file
Summer-luna Nov 12, 2023
96c0a73
fix: prisma incompatible
Summer-luna Nov 12, 2023
48a22cf
fix: style
Summer-luna Nov 12, 2023
e91cc94
feat: add id to record table and show in csv file
Summer-luna Dec 11, 2023
6f225ae
merge main
Summer-luna Dec 11, 2023
32de90b
refactor: name convention
Summer-luna Dec 11, 2023
07772b4
feat: add new billable hours table schema
Summer-luna Dec 15, 2023
5b1e223
feat: new ui interface for group by employee
Summer-luna Dec 16, 2023
9c716b1
fix: remove used imports
Summer-luna Dec 16, 2023
b27057a
refactor: create reusable FormObserver
Summer-luna Dec 17, 2023
468a68a
refactor: remove used imports
Summer-luna Dec 17, 2023
8832501
feat: create and update the billable hours
Summer-luna Dec 17, 2023
7b1dbbd
feat: new migration file
Summer-luna Dec 17, 2023
41eedca
feat: search billable hours based on projectId, employeeId, startDate…
Summer-luna Dec 18, 2023
e586e5e
reduce report table spacing
Summer-luna Dec 19, 2023
e93c68e
feat: update total billable and total precalculated hours
Summer-luna Dec 19, 2023
fece544
refactor: remove unused imports
Summer-luna Dec 19, 2023
64b939c
feat: updated report by project UI and data
Summer-luna Dec 22, 2023
3c61e99
fix: sort by percentage not work well
Summer-luna Dec 22, 2023
1d1f328
fix: new layout for report page
Summer-luna Dec 22, 2023
0ae112e
fix: theme switch bar width
Summer-luna Dec 22, 2023
22b04f9
refactor: remove unused imports
Summer-luna Dec 22, 2023
21be0ea
refactor: remove unused imports
Summer-luna Dec 22, 2023
84416f7
fix: refetch project with employee record after edit the billable hours
Summer-luna Dec 22, 2023
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
22,077 changes: 0 additions & 22,077 deletions package-lock.json

This file was deleted.

20 changes: 10 additions & 10 deletions packages/client/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import { Employee } from '@pages/Employee/Employee';
import { Employee } from '@pages/employee/Employee';

import { GraphqlProvider } from '@graphql/graphql-provider';
import { Project } from '@pages/Project/Project';
import { Track } from '@pages/Track/Track';
import { Project } from '@pages/project/Project';
import { Track } from '@pages/track/Track';
import { Paths } from '@constants/paths';
import { AdminLayout } from '@pages/Admin/AdminLayout';
import { AdminLayout } from '@pages/admin/AdminLayout';
import { ThemeProvider } from '@theme/theme.provider';
import { SettingsProvider } from '@context/setting.context';
import { EmployeeProvider } from '@context/employee.context';
import { DateProvider } from '@context/date.context';
import { TrackLayout } from '@pages/Track/components/TrackLayout';
import { Report } from '@pages/Report/Report';
import { Invoice } from '@pages/Invoice/Invoice';
import { TrackLayout } from '@pages/track/components/TrackLayout';
import { Report } from '@pages/report/Report';
import { Invoice } from '@pages/invoice/Invoice';
import enLocale from 'date-fns/locale/en-US';
import { InvoiceDetails } from '@pages/Invoice/InvoiceDetails';
import { InvoiceDetails } from '@pages/invoice/InvoiceDetails';
import { DateRangeProvider } from '@context/reportFilter.context';
import { Export } from '@pages/Invoice/Export';
import { NotFoundAdmin } from '@pages/Not_Find/NotFindAdmin';
import { Export } from '@pages/invoice/Export';
import { NotFoundAdmin } from '@pages/not-found/NotFindAdmin';
import { SnackBarProvider } from '@context/snackbar.context';
import { NavbarProvider } from '@context/navbar.context';

Expand Down
3 changes: 2 additions & 1 deletion packages/client/src/components/StyledComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ export const StyledTableHeadRow = styled(TableRow)(({ theme }) => ({
export const StyledTableDataRow = styled(TableRow)(({ theme }) => ({
'& .MuiTableCell-root': {
borderBottom: '1px dashed',
borderColor: theme.palette.mode === 'light' ? theme.palette.grey[200] : 'rgb(46, 50, 54)'
borderColor: theme.palette.mode === 'light' ? theme.palette.grey[200] : 'rgb(46, 50, 54)',
padding: 4
},
'&:hover': { backgroundColor: theme.palette.mode === 'light' ? theme.palette.grey[100] : alpha(theme.palette.grey[500], 0.08) }
}));
Expand Down
29 changes: 29 additions & 0 deletions packages/client/src/components/form/FormObserver.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useFormikContext } from 'formik';
import { FC, useEffect, useRef } from 'react';

interface FormObserverProps {
id: string;
handleOnChange: (value: number) => void;
}

interface FormValues {
[id: string]: number | string;
}

export const FormObserver: FC<FormObserverProps> = ({ id, handleOnChange }) => {
const { values } = useFormikContext<FormValues>();
const valueRef = useRef(values);

useEffect(() => {
if (values[id] === valueRef.current[id] || values[id] < 0) return;
const timeId = setTimeout(() => {
const value = values[id] === 0 || values[id] === '' ? 0 : (values[id] as number);
handleOnChange(value);
}, 1000);
valueRef.current = values;

return () => clearTimeout(timeId);
}, [values]);

return null;
};
3 changes: 2 additions & 1 deletion packages/client/src/components/form/ObserverTextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ export const ObserverTextInput: FC<TextInputProps> = (props) => {
error={!!errors[props.name]}
helperText={(touched[props.name] && errors[props.name]) as string}
sx={{
'.MuiFormHelperText-root ': { width: '120px', marginRight: 0 }
'.MuiFormHelperText-root ': { width: '120px', marginRight: 0 },
...props.sx
}}
/>
</FormControl>
Expand Down
8 changes: 1 addition & 7 deletions packages/client/src/components/switch/switchBtn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,5 @@ interface SwitchBtnProps {
export const SwitchBtn: FC<SwitchBtnProps> = ({ onClick, open = true }) => {
const { settings } = useSettings();

return (
<FormControlLabel
control={<MaterialUISwitch sx={{ m: 1 }} defaultChecked={settings.theme !== 'light'} onClick={onClick} />}
label={open ? 'Theme switch' : ''}
sx={{ minWidth: '200px' }}
/>
);
return <FormControlLabel control={<MaterialUISwitch sx={{ m: 1 }} defaultChecked={settings.theme !== 'light'} onClick={onClick} />} label={open ? 'Theme switch' : ''} />;
};
11 changes: 11 additions & 0 deletions packages/client/src/graphql/billable-hours/billable-hours.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
mutation createOrUpdateBillableHours($input: BillableHoursCreateInput!) {
createOrUpdateBillableHours(input: $input) {
id
employeeId
projectId
precalculatedHours
billableHours
startDate
endDate
}
}
66 changes: 66 additions & 0 deletions packages/client/src/graphql/billable-hours/billable-hours.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* Generated File DO NOT EDIT. */
/* tslint:disable */
import * as Types from '../graphql';

import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type CreateOrUpdateBillableHoursMutationVariables = Types.Exact<{
input: Types.BillableHoursCreateInput;
}>;

export type CreateOrUpdateBillableHoursMutation = {
__typename?: 'Mutation';
createOrUpdateBillableHours: {
__typename?: 'BillableHoursModel';
id: string;
employeeId: string;
projectId: string;
precalculatedHours: number;
billableHours: number;
startDate: any;
endDate: any;
};
};

export const CreateOrUpdateBillableHoursDocument = gql`
mutation createOrUpdateBillableHours($input: BillableHoursCreateInput!) {
createOrUpdateBillableHours(input: $input) {
id
employeeId
projectId
precalculatedHours
billableHours
startDate
endDate
}
}
`;
export type CreateOrUpdateBillableHoursMutationFn = Apollo.MutationFunction<CreateOrUpdateBillableHoursMutation, CreateOrUpdateBillableHoursMutationVariables>;

/**
* __useCreateOrUpdateBillableHoursMutation__
*
* To run a mutation, you first call `useCreateOrUpdateBillableHoursMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useCreateOrUpdateBillableHoursMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [createOrUpdateBillableHoursMutation, { data, loading, error }] = useCreateOrUpdateBillableHoursMutation({
* variables: {
* input: // value for 'input'
* },
* });
*/
export function useCreateOrUpdateBillableHoursMutation(
baseOptions?: Apollo.MutationHookOptions<CreateOrUpdateBillableHoursMutation, CreateOrUpdateBillableHoursMutationVariables>
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useMutation<CreateOrUpdateBillableHoursMutation, CreateOrUpdateBillableHoursMutationVariables>(CreateOrUpdateBillableHoursDocument, options);
}
export type CreateOrUpdateBillableHoursMutationHookResult = ReturnType<typeof useCreateOrUpdateBillableHoursMutation>;
export type CreateOrUpdateBillableHoursMutationResult = Apollo.MutationResult<CreateOrUpdateBillableHoursMutation>;
export type CreateOrUpdateBillableHoursMutationOptions = Apollo.BaseMutationOptions<CreateOrUpdateBillableHoursMutation, CreateOrUpdateBillableHoursMutationVariables>;
4 changes: 4 additions & 0 deletions packages/client/src/graphql/employee/employee.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ query getEmployeesWithRecord($startDate: DateTime!, $endDate: DateTime!) {
status
workHours
indirectHours
precalculatedHours
billableHours
inner {
projectId
Expand All @@ -22,6 +23,8 @@ query getEmployeesWithRecord($startDate: DateTime!, $endDate: DateTime!) {
projectWorkHours
projectPercentage
projectIndirectHours
precalculatedHours
billableHours
}
}
}
Expand All @@ -45,6 +48,7 @@ query getProjectWithEmployeeRecords($startDate: DateTime!, $endDate: DateTime!)
employeeWorkHours
employeeIndirectHours
employeePercentage
employeeBillableHours
}

}
Expand Down
8 changes: 8 additions & 0 deletions packages/client/src/graphql/employee/employee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export type GetEmployeesWithRecordQuery = {
status: string;
workHours: number;
indirectHours: number;
precalculatedHours: number;
billableHours: number;
inner: Array<{
__typename?: 'EmployeeWithRecordInner';
Expand All @@ -32,6 +33,8 @@ export type GetEmployeesWithRecordQuery = {
projectWorkHours: number;
projectPercentage: string;
projectIndirectHours: number;
precalculatedHours?: number | null;
billableHours?: number | null;
}>;
}>;
};
Expand Down Expand Up @@ -63,6 +66,7 @@ export type GetProjectWithEmployeeRecordsQuery = {
employeeWorkHours: number;
employeeIndirectHours: number;
employeePercentage: string;
employeeBillableHours: number;
}>;
}>;
};
Expand Down Expand Up @@ -178,6 +182,7 @@ export const GetEmployeesWithRecordDocument = gql`
status
workHours
indirectHours
precalculatedHours
billableHours
inner {
projectId
Expand All @@ -186,6 +191,8 @@ export const GetEmployeesWithRecordDocument = gql`
projectWorkHours
projectPercentage
projectIndirectHours
precalculatedHours
billableHours
}
}
}
Expand Down Expand Up @@ -239,6 +246,7 @@ export const GetProjectWithEmployeeRecordsDocument = gql`
employeeWorkHours
employeeIndirectHours
employeePercentage
employeeBillableHours
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/graphql/graphql-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { FC, useEffect } from 'react';
import { ApolloClient, ApolloProvider, from, HttpLink, InMemoryCache } from '@apollo/client';
import { useSettings } from '@context/setting.context';
import { LoadingScreen } from '@components/loading-screen';
import { LoadingScreen } from '@components/LoadingScreen';

export interface GraphqlProviderProps {
children: React.ReactNode;
Expand Down
31 changes: 31 additions & 0 deletions packages/client/src/graphql/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,26 @@ export type BatchSendSlackMessageInput = {
message: Scalars['String'];
};

export type BillableHoursCreateInput = {
billableHours: Scalars['Float'];
employeeId: Scalars['String'];
endDate: Scalars['DateTime'];
precalculatedHours: Scalars['Float'];
projectId: Scalars['String'];
startDate: Scalars['DateTime'];
};

export type BillableHoursModel = {
__typename?: 'BillableHoursModel';
billableHours: Scalars['Float'];
employeeId: Scalars['String'];
endDate: Scalars['DateTime'];
id: Scalars['ID'];
precalculatedHours: Scalars['Float'];
projectId: Scalars['String'];
startDate: Scalars['DateTime'];
};

export type ClickUpStatuses = {
__typename?: 'ClickUpStatuses';
color: Scalars['String'];
Expand Down Expand Up @@ -139,15 +159,18 @@ export type EmployeeWithRecord = {
indirectHours: Scalars['Float'];
inner: Array<EmployeeWithRecordInner>;
name: Scalars['String'];
precalculatedHours: Scalars['Float'];
status: Scalars['String'];
workHours: Scalars['Float'];
};

export type EmployeeWithRecordInner = {
__typename?: 'EmployeeWithRecordInner';
billableHours?: Maybe<Scalars['Float']>;
contractTypeId: Scalars['Float'];
fte: Scalars['Float'];
isBillable: Scalars['Boolean'];
precalculatedHours?: Maybe<Scalars['Float']>;
projectId: Scalars['String'];
projectIndirectHours: Scalars['Float'];
projectName: Scalars['String'];
Expand Down Expand Up @@ -274,6 +297,7 @@ export type Mutation = {
batchSendingMessages: BatchResponseModel;
createAndAddClickUpTaskToInvoice: ClickUpTaskModel;
createClickUpTask: ClickUpTaskModel;
createOrUpdateBillableHours: BillableHoursModel;
createOrUpdateInvoice: InvoiceModel;
deleteComment: CommentModel;
deleteEmployees: EmployeeDeleteReturnModel;
Expand Down Expand Up @@ -322,6 +346,10 @@ export type MutationCreateClickUpTaskArgs = {
task: ClickUpTaskCreateInput;
};

export type MutationCreateOrUpdateBillableHoursArgs = {
input: BillableHoursCreateInput;
};

export type MutationCreateOrUpdateInvoiceArgs = {
invoice: InvoiceCreateInput;
};
Expand Down Expand Up @@ -442,6 +470,7 @@ export type ProjectWithEmployeeRecords = {

export type ProjectWithEmployeeRecordsInner = {
__typename?: 'ProjectWithEmployeeRecordsInner';
employeeBillableHours: Scalars['Float'];
employeeId: Scalars['String'];
employeeIndirectHours: Scalars['Float'];
employeeName: Scalars['String'];
Expand Down Expand Up @@ -538,6 +567,7 @@ export type RecordInsertOrUpdateModel = {
date: Scalars['DateTime'];
employeeId: Scalars['ID'];
hours: Scalars['Float'];
id?: Maybe<Scalars['String']>;
projectId: Scalars['ID'];
};

Expand All @@ -547,6 +577,7 @@ export type RecordModel = {
employee: EmployeeModel;
employeeId: Scalars['ID'];
hours: Scalars['Float'];
id?: Maybe<Scalars['String']>;
project: ProjectModel;
projectId: Scalars['ID'];
};
Expand Down
1 change: 1 addition & 0 deletions packages/client/src/graphql/record/record.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mutation deleteRecord($input: RecordDeleteInput!) {

query getRecordsByDateRange($input: DateRangeInput!) {
getRecordsByDateRange(input: $input) {
id
date
hours
employee {
Expand Down
2 changes: 2 additions & 0 deletions packages/client/src/graphql/record/record.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export type GetRecordsByDateRangeQuery = {
__typename?: 'Query';
getRecordsByDateRange: Array<{
__typename?: 'RecordModel';
id?: string | null;
date: any;
hours: number;
employee: { __typename?: 'EmployeeModel'; name: string };
Expand Down Expand Up @@ -107,6 +108,7 @@ export type DeleteRecordMutationOptions = Apollo.BaseMutationOptions<DeleteRecor
export const GetRecordsByDateRangeDocument = gql`
query getRecordsByDateRange($input: DateRangeInput!) {
getRecordsByDateRange(input: $input) {
id
date
hours
employee {
Expand Down
Loading
Loading