diff --git a/src/containers/Projects/components/ProjectBillableTypeSuggestField.tsx b/src/containers/Projects/components/ProjectBillableTypeSuggestField.tsx new file mode 100644 index 000000000..12996c5b8 --- /dev/null +++ b/src/containers/Projects/components/ProjectBillableTypeSuggestField.tsx @@ -0,0 +1,132 @@ +// @ts-nocheck +import React from 'react'; +import intl from 'react-intl-universal'; +import { Menu, MenuItem } from '@blueprintjs/core'; +import { Suggest } from '@blueprintjs/select'; +import { FormattedMessage as T } from '@/components'; + +import classNames from 'classnames'; +import { CLASSES } from '@/constants/classes'; + +/** + * @param {*} billableType + * @param {*} param1 + * @returns {JSX.Element} + */ +const billableTypeItemRenderer = ( + billableType, + { handleClick, modifiers, query }, +) => { + return ( + + ); +}; + +/** + * + * @param {*} query + * @param {*} billableType + * @param {*} _index + * @param {*} exactMatch + * @returns + */ +const billableTypeItemPredicate = (query, billableType, _index, exactMatch) => { + const normalizedTitle = billableType.name.toLowerCase(); + const normalizedQuery = query.toLowerCase(); + + if (exactMatch) { + return normalizedTitle === normalizedQuery; + } else { + return ( + `${billableType.name}. ${normalizedTitle}`.indexOf(normalizedQuery) >= 0 + ); + } +}; + +/** + * + * @param inputValue + * @returns + */ +const billableTypeInputValueRenderer = (inputValue) => { + if (inputValue) { + return inputValue.name.toString(); + } + return ''; +}; + +/** + * Project billable suggest field. + * @param + */ +export function ProjectBillableSuggestField({ + billableType, + initialBillableTypeId, + selectedBillableTypeId, + + defautlSelectText = 'Placeholder Type...', + onBillableTypeSelected, + popoverFill = false, + + ...suggestProps +}) { + const initialBillableType = React.useMemo( + () => billableType.find((b) => b.id === initialBillableTypeId), + [initialBillableTypeId, billableType], + ); + + const [selectedBillableType, setSelectedBillableType] = React.useState( + initialBillableType || null, + ); + + React.useEffect(() => { + if (typeof selectedBillableTypeId !== 'undefined') { + const billableType = selectedBillableTypeId + ? billableType.find((a) => a.id === selectedBillableTypeId) + : null; + setSelectedBillableType(billableType); + } + }, [selectedBillableTypeId, billableType, setSelectedBillableType]); + + /** + * + * @param {*} billableType + * @returns + */ + const billableTypetemSelect = React.useCallback( + (billableType) => { + if (billableType.id) { + setSelectedBillableType({ ...billableType }); + onBillableTypeSelected && onBillableTypeSelected(billableType); + } + }, + [setSelectedBillableType, onBillableTypeSelected], + ); + + const billableTypeSelectProps = { + itemRenderer: billableTypeItemRenderer, + itemPredicate: billableTypeItemPredicate, + inputValueRenderer: billableTypeInputValueRenderer, + }; + return ( + + ); +} diff --git a/src/containers/Projects/components/ProjectSuggestField.tsx b/src/containers/Projects/components/ProjectSuggestField.tsx index 56cd61df0..216606a5f 100644 --- a/src/containers/Projects/components/ProjectSuggestField.tsx +++ b/src/containers/Projects/components/ProjectSuggestField.tsx @@ -48,15 +48,13 @@ export function ProjectSuggestField({ */ const projectsItemRenderer = (project, { handleClick, modifiers, query }) => { return ( - - } - disabled={modifiers.disabled} - key={project.id} - text={project.name} - onClick={handleClick} - /> - + } + disabled={modifiers.disabled} + key={project.id} + text={project.name} + onClick={handleClick} + /> ); }; @@ -133,20 +131,14 @@ const AvatarSelect = ({ text }) => { return {firstLettersArgs(text?.name)}; }; -const MenuContent = styled(Menu)` - .bp3-menu { - margin: 5px; - } -`; - const AvaterContent = styled.div` display: inline-block; background: #adbcc9; text-align: center; font-weight: 400; color: #fff; - height: 25px; - width: 25px; - line-height: 25px; + height: 22px; + width: 22px; + line-height: 22px; font-size: 12px; `; diff --git a/src/containers/Projects/components/index.ts b/src/containers/Projects/components/index.ts index b27dbd340..b0dd663ed 100644 --- a/src/containers/Projects/components/index.ts +++ b/src/containers/Projects/components/index.ts @@ -5,4 +5,5 @@ export * from './TaskSelect'; export * from './ProjectsSelect'; export * from './ProjectMultiSelect' export * from './FInputGroupComponent'; -export * from './ProjectSuggestField' \ No newline at end of file +export * from './ProjectSuggestField' +export * from './ProjectBillableTypeSuggestField' \ No newline at end of file diff --git a/src/containers/Projects/containers/ProjectBillableEntriesFormDialog/ProjectBillableEntriesFormFields.tsx b/src/containers/Projects/containers/ProjectBillableEntriesFormDialog/ProjectBillableEntriesFormFields.tsx index 636ea8966..b0f771eba 100644 --- a/src/containers/Projects/containers/ProjectBillableEntriesFormDialog/ProjectBillableEntriesFormFields.tsx +++ b/src/containers/Projects/containers/ProjectBillableEntriesFormDialog/ProjectBillableEntriesFormFields.tsx @@ -9,6 +9,8 @@ import { FieldRequiredHint, FormattedMessage as T, } from '@/components'; +import { ProjectBillableSuggestField } from '../../components'; +import { billableTypeOption } from '../common'; import { ProjectRowDivider, ProjectEntiresBox } from './components'; import { useProjectBillableEntriesFormContext } from './ProjectBillableEntriesFormProvider'; @@ -20,8 +22,6 @@ export default function ProjectBillableEntriesFormFields() { // Formik context. const { values } = useFormikContext(); - const { billableEntries } = useProjectBillableEntriesFormContext(); - return (
{/*------------ Filter by Date -----------*/} @@ -37,14 +37,14 @@ export default function ProjectBillableEntriesFormFields() { {/*------------ Filter by Type -----------*/} } labelInfo={} > - + - +
); } diff --git a/src/containers/Projects/containers/ProjectBillableEntriesFormDialog/ProjectBillableEntriesFormProvider.tsx b/src/containers/Projects/containers/ProjectBillableEntriesFormDialog/ProjectBillableEntriesFormProvider.tsx index 589bd3f89..4f9aa522f 100644 --- a/src/containers/Projects/containers/ProjectBillableEntriesFormDialog/ProjectBillableEntriesFormProvider.tsx +++ b/src/containers/Projects/containers/ProjectBillableEntriesFormDialog/ProjectBillableEntriesFormProvider.tsx @@ -1,7 +1,6 @@ // @ts-nocheck import React from 'react'; -import { useProjectBillableEntries } from '../../hooks'; import { DialogContent } from '@/components'; const ProjectBillableEntriesFormContext = React.createContext(); @@ -16,31 +15,14 @@ function ProjectBillableEntriesFormProvider({ projectId, ...props }) { - // Handle fetch project billable entries. - const { - data: { billableEntries }, - isLoading: isProjectBillableEntriesLoading, - } = useProjectBillableEntries( - projectId, - { - billable_type: 'expense', - to_date: '', - }, - { - enabled: !!projectId, - keepPreviousData: true, - }, - ); - //state provider. const provider = { dialogName, projectId, - billableEntries, }; return ( - + ); diff --git a/src/containers/Projects/containers/common/modalChargeOptions.ts b/src/containers/Projects/containers/common/modalChargeOptions.ts index e1dd36b5a..f4462b3c0 100644 --- a/src/containers/Projects/containers/common/modalChargeOptions.ts +++ b/src/containers/Projects/containers/common/modalChargeOptions.ts @@ -4,7 +4,10 @@ import intl from 'react-intl-universal'; export const taskChargeOptions = [ { name: intl.get('project_task.dialog.hourly_rate'), value: 'TIME' }, { name: intl.get('project_task.dialog.fixed_price'), value: 'FIXED' }, - { name: intl.get('project_task.dialog.non_chargeable'), value: 'NON_CHARGABLE' }, + { + name: intl.get('project_task.dialog.non_chargeable'), + value: 'NON_CHARGABLE', + }, ]; export const expenseChargeOption = [ @@ -16,3 +19,12 @@ export const expenseChargeOption = [ { name: intl.get('expenses.dialog.custom_pirce'), value: 'custom_pirce' }, { name: intl.get('expenses.dialog.non_chargeable'), value: 'non_chargeable' }, ]; + +export const billableTypeOption = [ + { name: intl.get('project_billable_entries.dialog.task'), value: 'Task' }, + { name: intl.get('project_billable_entries.dialog.bill'), value: 'Bill' }, + { + name: intl.get('project_billable_entries.dialog.expense'), + value: 'Expense', + }, +]; diff --git a/src/containers/Projects/hooks/projectBillableEntries.tsx b/src/containers/Projects/hooks/projectBillableEntries.tsx index 72f63a90f..a2da2b86f 100644 --- a/src/containers/Projects/hooks/projectBillableEntries.tsx +++ b/src/containers/Projects/hooks/projectBillableEntries.tsx @@ -12,7 +12,7 @@ import t from './type'; */ export function useProjectBillableEntries(projectId, query, props) { return useRequestQuery( - [t.PROJECT_BILLABLE_ENTRIES, projectId], + [t.PROJECT_BILLABLE_ENTRIES, projectId, query], { method: 'get', url: `projects/${projectId}/billable/entries`, @@ -20,9 +20,7 @@ export function useProjectBillableEntries(projectId, query, props) { }, { select: (res) => res.data.billable_entries, - defaultData: { - billableEntries: [], - }, + defaultData: {}, ...props, }, ); diff --git a/src/lang/en/index.json b/src/lang/en/index.json index 64b3b0c71..65180dba4 100644 --- a/src/lang/en/index.json +++ b/src/lang/en/index.json @@ -2212,5 +2212,8 @@ "project_invoicing.dialog.bill_to": "Bill To", "project_billable_entries.dialog.label": "Add Project Entries", "project_billable_entries.dialog.filter_by_date": "Filter by Date", - "project_billable_entries.dialog.filter_by_type":"Filter by Type" + "project_billable_entries.dialog.filter_by_type": "Filter by Type", + "project_billable_entries.dialog.expense": "Expense", + "project_billable_entries.dialog.task": "Task", + "project_billable_entries.dialog.bill": "Bill" } \ No newline at end of file