From 7f0425df6e9037d6c48e0738e3203c4ba6842eeb Mon Sep 17 00:00:00 2001 From: tnagorra Date: Sat, 7 Sep 2024 09:17:29 +0545 Subject: [PATCH] Add indent settings for entry - Refactor list grouping --- src/utils/common.ts | 21 +-- src/utils/constants.ts | 1 + src/utils/types.ts | 13 +- .../DailyJournal/AddWorkItemDialog/index.tsx | 2 +- .../AddWorkItemDialog/styles.module.css | 2 +- .../DayView/WorkItemRow/index.tsx | 2 - src/views/DailyJournal/DayView/index.tsx | 133 ++++++++++-------- src/views/DailyJournal/StartSidebar/index.tsx | 11 +- src/views/DailyJournal/index.tsx | 18 +++ src/views/Settings/index.tsx | 6 + 10 files changed, 131 insertions(+), 78 deletions(-) diff --git a/src/utils/common.ts b/src/utils/common.ts index 88ea329..654d975 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -223,11 +223,13 @@ export function sortByAttributes( attributes: ATTRIBUTE[], sortFn: (a: LIST_ITEM, b: LIST_ITEM, attr: ATTRIBUTE) => number, ): LIST_ITEM[] { + if (attributes.length <= 0) { + return list; + } + const newList = [...list]; newList.sort( (a, b) => { - let sortResult = 0; - for (let i = 0; i < attributes.length; i += 1) { const currentSortResult = sortFn( a, @@ -236,12 +238,10 @@ export function sortByAttributes( ); if (currentSortResult !== 0) { - sortResult = currentSortResult; - break; + return currentSortResult; } } - - return sortResult; + return 0; }, ); @@ -249,7 +249,7 @@ export function sortByAttributes( } type GroupedItem = { - key: string; + groupKey: string; type: 'heading'; value: LIST_ITEM; attribute: ATTRIBUTE; @@ -265,6 +265,7 @@ export function groupListByAttributes( list: LIST_ITEM[], attributes: ATTRIBUTE[], compareItemAttributes: (a: LIST_ITEM, b: LIST_ITEM, attribute: ATTRIBUTE) => boolean, + getGroupKey: (item: LIST_ITEM, attributes: ATTRIBUTE[]) => string, ): GroupedItem[] { if (isNotDefined(list) || list.length === 0) { return []; @@ -272,12 +273,13 @@ export function groupListByAttributes( const groupedItems = list.flatMap((listItem, listIndex) => { if (listIndex === 0) { + const groupKey = getGroupKey(listItem, attributes); const headings = attributes.map((attribute, i) => ({ type: 'heading' as const, value: listItem, attribute, level: i, - key: `heading-${listIndex}-${i}`, + groupKey, })); return [ @@ -311,6 +313,7 @@ export function groupListByAttributes( ]; } + const groupKey = getGroupKey(listItem, attributes); const headings = attributes.map((attribute, i) => { if (i < attributeMismatchIndex) { return undefined; @@ -321,7 +324,7 @@ export function groupListByAttributes( value: listItem, attribute, level: i, - key: `heading-${listIndex}-${i}`, + groupKey, }; }).filter(isDefined); diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 3b4931c..352e9ff 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -7,6 +7,7 @@ export const defaultConfigValue: ConfigStorage = { defaultTaskType: undefined, defaultTaskStatus: 'DONE', editingMode: 'normal', + indent: true, compactTextArea: false, checkboxForStatus: false, startSidebarShown: window.innerWidth >= 900, diff --git a/src/utils/types.ts b/src/utils/types.ts index 3c4b306..5c31fa9 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -23,7 +23,7 @@ export type WorkItemStatus = TimeEntryStatusEnum; export type WorkItem = Omit & { clientId: string }; export type DailyJournalAttributeKeys = 'project' | 'contract' | 'task' | 'status'; -export interface DailyJournalAttributeOrder { +export interface DailyJournalAttribute { key: DailyJournalAttributeKeys; sortDirection: number; } @@ -36,13 +36,18 @@ export interface DailyJournalGrouping { export type ConfigStorage = { defaultTaskType: WorkItemType | undefined, defaultTaskStatus: WorkItemStatus, + editingMode: EditingMode, + checkboxForStatus: boolean, - startSidebarShown: boolean, - endSidebarShown: boolean, compactTextArea: boolean, - dailyJournalAttributeOrder: DailyJournalAttributeOrder[]; + indent: boolean, + + dailyJournalAttributeOrder: DailyJournalAttribute[]; dailyJournalGrouping: DailyJournalGrouping; + + startSidebarShown: boolean, + endSidebarShown: boolean, } export interface GeneralEvent { diff --git a/src/views/DailyJournal/AddWorkItemDialog/index.tsx b/src/views/DailyJournal/AddWorkItemDialog/index.tsx index 592623a..089de64 100644 --- a/src/views/DailyJournal/AddWorkItemDialog/index.tsx +++ b/src/views/DailyJournal/AddWorkItemDialog/index.tsx @@ -94,7 +94,7 @@ function AddWorkItemDialog(props: Props) { focusElementRef={titleInputRef} >
- Please select a task to add the workitems + Please select a task to add new entry
{ if (attr.key === 'status') { return item.status; @@ -102,6 +102,7 @@ function DayView(props: Props) { const formattedDate = dateFormatter.format(new Date(selectedDate)); const formattedRelativeDate = useFormattedRelativeDate(selectedDate); + const totalHours = useMemo( () => { if (isDefined(workItems)) { @@ -115,11 +116,13 @@ function DayView(props: Props) { const { dailyJournalAttributeOrder, - dailyJournalGrouping, + dailyJournalGrouping: { + groupLevel, + joinLevel, + }, + indent, } = storedConfig; - const { groupLevel, joinLevel } = dailyJournalGrouping; - const groupedItems = useMemo(() => { if (isNotDefined(taskById) || isNotDefined(workItems)) { return []; @@ -130,8 +133,8 @@ function DayView(props: Props) { dailyJournalAttributeOrder, (a, b, attr) => ( compareString( - getWorkItemAttribute(a, attr), - getWorkItemAttribute(b, attr), + getWorkItemLabelFromAttr(a, attr), + getWorkItemLabelFromAttr(b, attr), attr.sortDirection, ) ), @@ -141,16 +144,20 @@ function DayView(props: Props) { sortedWorkItems, dailyJournalAttributeOrder.slice(0, groupLevel), (a, b, attr) => { - const aValue = getWorkItemAttribute(a, attr); - const bValue = getWorkItemAttribute(b, attr); + const aValue = getWorkItemLabelFromAttr(a, attr); + const bValue = getWorkItemLabelFromAttr(b, attr); return aValue === bValue; }, + (item, attrs) => { + const values = attrs.map((attr) => getWorkItemLabelFromAttr(item, attr)).join(';'); + return values; + }, ); }, [ taskById, workItems, - getWorkItemAttribute, + getWorkItemLabelFromAttr, dailyJournalAttributeOrder, groupLevel, ]); @@ -185,75 +192,87 @@ function DayView(props: Props) {
{groupedItems.map((groupedItem) => { if (groupedItem.type === 'heading') { - const levelDiff = groupLevel - joinLevel; - - const headingText = getWorkItemAttribute( - groupedItem.value, - groupedItem.attribute, - ); + // Main Heading + // NOTE: Need to add 1 as groupLevel and level starts from 1 and 0 resp. + if (groupedItem.level + 1 < (groupLevel - joinLevel + 1)) { + const headingText = getWorkItemLabelFromAttr( + groupedItem.value, + groupedItem.attribute, + ); - if (groupedItem.level < levelDiff) { const Heading = `h${bound(groupedItem.level + 2, 2, 4)}` as unknown as ElementType; return ( - + {indent && } {headingText} ); } - if (groupedItem.level < (groupLevel - 1)) { - return null; + // Sub Headings + // NOTE: We only need to show one subheading after the main headings + // NOTE: Need to add 1 as groupLevel and level starts from 1 and 0 resp. + if (groupedItem.level + 1 === groupLevel) { + return ( +

+ {indent && ( + + )} + {dailyJournalAttributeOrder.map((attribute, i) => { + if (i >= groupLevel) { + return null; + } + + const currentLabel = getWorkItemLabelFromAttr( + groupedItem.value, + attribute, + ); + + if (i < (groupLevel - joinLevel)) { + return null; + } + + return ( + + {i > (groupLevel - joinLevel) && ( +
+ )} +
{currentLabel}
+ + ); + })} +

+ ); } - return ( -

- - {dailyJournalAttributeOrder.map((attribute, i) => { - if (i >= groupLevel) { - return null; - } - - const currentLabel = getWorkItemAttribute( - groupedItem.value, - attribute, - ); - - if (i < (groupLevel - joinLevel)) { - return null; - } - - return ( - - {i > (groupLevel - joinLevel) && ( -
- )} -
{currentLabel}
- - ); - })} -

- ); + return null; } const taskDetails = taskById?.[groupedItem.value.task]; - if (!taskDetails) { return null; } return ( -
- +
+ {indent && ( + + )} void; draggableAttributes?: DraggableAttributes; draggableListeners?: SyntheticListenerMap | undefined; @@ -99,7 +99,7 @@ function Item(props: ItemProps) { interface SortableItemProps { className?: string; - attribute: DailyJournalAttributeOrder; + attribute: DailyJournalAttribute; } function SortableItem(props: SortableItemProps) { @@ -247,7 +247,10 @@ function StartSidebar(props: Props) { strategy={verticalListSortingStrategy} > {storedConfig.dailyJournalAttributeOrder.map((attribute) => ( - + ))} diff --git a/src/views/DailyJournal/index.tsx b/src/views/DailyJournal/index.tsx index b8ae8b0..fe0bb2d 100644 --- a/src/views/DailyJournal/index.tsx +++ b/src/views/DailyJournal/index.tsx @@ -103,6 +103,24 @@ const MY_TIME_ENTRIES_QUERY = gql` } `; +/* +query MyQuery { + private { + allTimeEntries(filters: {statuses: TODO, users: "9"}) { + clientId + id + description + date + startTime + duration + status + taskId + type + } + } +} +*/ + const BULK_TIME_ENTRY_MUTATION = gql` mutation BulkTimeEntry($timeEntries: [TimeEntryBulkCreateInput!], $deleteIds: [ID!]) { private { diff --git a/src/views/Settings/index.tsx b/src/views/Settings/index.tsx index f8c6221..d5a4841 100644 --- a/src/views/Settings/index.tsx +++ b/src/views/Settings/index.tsx @@ -85,6 +85,12 @@ export function Component() { value={storedConfig.checkboxForStatus} onChange={setConfigFieldValue} /> +