Skip to content

Commit d8f521a

Browse files
committed
Add indent settings for entry
- Refactor list grouping
1 parent d5b3d5e commit d8f521a

File tree

10 files changed

+125
-72
lines changed

10 files changed

+125
-72
lines changed

src/utils/common.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -223,11 +223,13 @@ export function sortByAttributes<LIST_ITEM, ATTRIBUTE>(
223223
attributes: ATTRIBUTE[],
224224
sortFn: (a: LIST_ITEM, b: LIST_ITEM, attr: ATTRIBUTE) => number,
225225
): LIST_ITEM[] {
226+
if (attributes.length <= 0) {
227+
return list;
228+
}
229+
226230
const newList = [...list];
227231
newList.sort(
228232
(a, b) => {
229-
let sortResult = 0;
230-
231233
for (let i = 0; i < attributes.length; i += 1) {
232234
const currentSortResult = sortFn(
233235
a,
@@ -236,20 +238,18 @@ export function sortByAttributes<LIST_ITEM, ATTRIBUTE>(
236238
);
237239

238240
if (currentSortResult !== 0) {
239-
sortResult = currentSortResult;
240-
break;
241+
return currentSortResult;
241242
}
242243
}
243-
244-
return sortResult;
244+
return 0;
245245
},
246246
);
247247

248248
return newList;
249249
}
250250

251251
type GroupedItem<LIST_ITEM, ATTRIBUTE> = {
252-
key: string;
252+
groupKey: string;
253253
type: 'heading';
254254
value: LIST_ITEM;
255255
attribute: ATTRIBUTE;
@@ -265,19 +265,21 @@ export function groupListByAttributes<LIST_ITEM, ATTRIBUTE>(
265265
list: LIST_ITEM[],
266266
attributes: ATTRIBUTE[],
267267
compareItemAttributes: (a: LIST_ITEM, b: LIST_ITEM, attribute: ATTRIBUTE) => boolean,
268+
getGroupKey: (item: LIST_ITEM, attributes: ATTRIBUTE[]) => string,
268269
): GroupedItem<LIST_ITEM, ATTRIBUTE>[] {
269270
if (isNotDefined(list) || list.length === 0) {
270271
return [];
271272
}
272273

273274
const groupedItems = list.flatMap((listItem, listIndex) => {
274275
if (listIndex === 0) {
276+
const groupKey = getGroupKey(listItem, attributes);
275277
const headings = attributes.map((attribute, i) => ({
276278
type: 'heading' as const,
277279
value: listItem,
278280
attribute,
279281
level: i,
280-
key: `heading-${listIndex}-${i}`,
282+
groupKey,
281283
}));
282284

283285
return [
@@ -311,6 +313,7 @@ export function groupListByAttributes<LIST_ITEM, ATTRIBUTE>(
311313
];
312314
}
313315

316+
const groupKey = getGroupKey(listItem, attributes);
314317
const headings = attributes.map((attribute, i) => {
315318
if (i < attributeMismatchIndex) {
316319
return undefined;
@@ -321,7 +324,7 @@ export function groupListByAttributes<LIST_ITEM, ATTRIBUTE>(
321324
value: listItem,
322325
attribute,
323326
level: i,
324-
key: `heading-${listIndex}-${i}`,
327+
groupKey,
325328
};
326329
}).filter(isDefined);
327330

src/utils/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export const defaultConfigValue: ConfigStorage = {
77
defaultTaskType: undefined,
88
defaultTaskStatus: 'DONE',
99
editingMode: 'normal',
10+
indent: true,
1011
compactTextArea: false,
1112
checkboxForStatus: false,
1213
startSidebarShown: window.innerWidth >= 900,

src/utils/types.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export type WorkItemStatus = TimeEntryStatusEnum;
2323
export type WorkItem = Omit<TimeEntryBulkCreateInput, 'clientId'> & { clientId: string };
2424

2525
export type DailyJournalAttributeKeys = 'project' | 'contract' | 'task' | 'status';
26-
export interface DailyJournalAttributeOrder {
26+
export interface DailyJournalAttribute {
2727
key: DailyJournalAttributeKeys;
2828
sortDirection: number;
2929
}
@@ -36,13 +36,18 @@ export interface DailyJournalGrouping {
3636
export type ConfigStorage = {
3737
defaultTaskType: WorkItemType | undefined,
3838
defaultTaskStatus: WorkItemStatus,
39+
3940
editingMode: EditingMode,
41+
4042
checkboxForStatus: boolean,
41-
startSidebarShown: boolean,
42-
endSidebarShown: boolean,
4343
compactTextArea: boolean,
44-
dailyJournalAttributeOrder: DailyJournalAttributeOrder[];
44+
indent: boolean,
45+
46+
dailyJournalAttributeOrder: DailyJournalAttribute[];
4547
dailyJournalGrouping: DailyJournalGrouping;
48+
49+
startSidebarShown: boolean,
50+
endSidebarShown: boolean,
4651
}
4752

4853
export interface GeneralEvent {

src/views/DailyJournal/AddWorkItemDialog/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ function AddWorkItemDialog(props: Props) {
9494
focusElementRef={titleInputRef}
9595
>
9696
<div>
97-
Please select a task to add the workitems
97+
Please select a task to add new entry
9898
</div>
9999
<TextInput
100100
inputElementRef={titleInputRef}

src/views/DailyJournal/AddWorkItemDialog/styles.module.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
}
4040

4141
&:hover {
42-
background-color: var(--color-background);
42+
background-color: var(--color-tertiary);
4343
}
4444
}
4545
}

src/views/DailyJournal/DayView/WorkItemRow/index.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,6 @@ function WorkItemRow(props: Props) {
9696
onChange,
9797
} = props;
9898

99-
console.log(workItem, contractId);
100-
10199
const { enums } = useContext(EnumsContext);
102100
const { screen } = useContext(SizeContext);
103101

src/views/DailyJournal/DayView/index.tsx

Lines changed: 70 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
sortByAttributes,
2626
} from '#utils/common';
2727
import {
28-
DailyJournalAttributeOrder,
28+
DailyJournalAttribute,
2929
EntriesAsList,
3030
WorkItem,
3131
} from '#utils/types';
@@ -73,7 +73,7 @@ function DayView(props: Props) {
7373

7474
const getWorkItemAttribute = useCallback((
7575
item: WorkItem,
76-
attr: DailyJournalAttributeOrder,
76+
attr: DailyJournalAttribute,
7777
) => {
7878
if (attr.key === 'status') {
7979
return item.status;
@@ -102,6 +102,7 @@ function DayView(props: Props) {
102102

103103
const formattedDate = dateFormatter.format(new Date(selectedDate));
104104
const formattedRelativeDate = useFormattedRelativeDate(selectedDate);
105+
105106
const totalHours = useMemo(
106107
() => {
107108
if (isDefined(workItems)) {
@@ -115,11 +116,13 @@ function DayView(props: Props) {
115116

116117
const {
117118
dailyJournalAttributeOrder,
118-
dailyJournalGrouping,
119+
dailyJournalGrouping: {
120+
groupLevel,
121+
joinLevel,
122+
},
123+
indent,
119124
} = storedConfig;
120125

121-
const { groupLevel, joinLevel } = dailyJournalGrouping;
122-
123126
const groupedItems = useMemo(() => {
124127
if (isNotDefined(taskById) || isNotDefined(workItems)) {
125128
return [];
@@ -146,6 +149,10 @@ function DayView(props: Props) {
146149

147150
return aValue === bValue;
148151
},
152+
(item, attrs) => {
153+
const values = attrs.map((attr) => getWorkItemAttribute(item, attr)).join(';');
154+
return values;
155+
},
149156
);
150157
}, [
151158
taskById,
@@ -185,75 +192,87 @@ function DayView(props: Props) {
185192
<div className={styles.newGroup}>
186193
{groupedItems.map((groupedItem) => {
187194
if (groupedItem.type === 'heading') {
188-
const levelDiff = groupLevel - joinLevel;
189-
190-
const headingText = getWorkItemAttribute(
191-
groupedItem.value,
192-
groupedItem.attribute,
193-
);
195+
// Main Heading
196+
// NOTE: Need to add 1 as groupLevel and level starts from 1 and 0 resp.
197+
if (groupedItem.level + 1 < (groupLevel - joinLevel + 1)) {
198+
const headingText = getWorkItemAttribute(
199+
groupedItem.value,
200+
groupedItem.attribute,
201+
);
194202

195-
if (groupedItem.level < levelDiff) {
196203
const Heading = `h${bound(groupedItem.level + 2, 2, 4)}` as unknown as ElementType;
197204

198205
return (
199206
<Heading
200-
key={groupedItem.key}
207+
key={`heading-${groupedItem.attribute.key}-of-${groupedItem.groupKey}`}
201208
className={styles.nestedHeading}
202209
>
203-
<Indent level={groupedItem.level} />
210+
{indent && <Indent level={groupedItem.level} />}
204211
{headingText}
205212
</Heading>
206213
);
207214
}
208215

209-
if (groupedItem.level < (groupLevel - 1)) {
210-
return null;
216+
// Sub Headings
217+
// NOTE: We only need to show one subheading after the main headings
218+
// NOTE: Need to add 1 as groupLevel and level starts from 1 and 0 resp.
219+
if (groupedItem.level + 1 === groupLevel) {
220+
return (
221+
<h4
222+
className={styles.joinedHeading}
223+
key={`sub-heading-group-of-${groupedItem.groupKey}`}
224+
>
225+
{indent && (
226+
<Indent
227+
level={groupedItem.level - joinLevel + 1}
228+
/>
229+
)}
230+
{dailyJournalAttributeOrder.map((attribute, i) => {
231+
if (i >= groupLevel) {
232+
return null;
233+
}
234+
235+
const currentLabel = getWorkItemAttribute(
236+
groupedItem.value,
237+
attribute,
238+
);
239+
240+
if (i < (groupLevel - joinLevel)) {
241+
return null;
242+
}
243+
244+
return (
245+
<Fragment key={`subheading-${attribute.key}-of-${groupedItem.groupKey}`}>
246+
{i > (groupLevel - joinLevel) && (
247+
<div className={styles.separator} />
248+
)}
249+
<div>{currentLabel}</div>
250+
</Fragment>
251+
);
252+
})}
253+
</h4>
254+
);
211255
}
212256

213-
return (
214-
<h4
215-
className={styles.joinedHeading}
216-
key={groupedItem.key}
217-
>
218-
<Indent level={groupedItem.level - joinLevel + 1} />
219-
{dailyJournalAttributeOrder.map((attribute, i) => {
220-
if (i >= groupLevel) {
221-
return null;
222-
}
223-
224-
const currentLabel = getWorkItemAttribute(
225-
groupedItem.value,
226-
attribute,
227-
);
228-
229-
if (i < (groupLevel - joinLevel)) {
230-
return null;
231-
}
232-
233-
return (
234-
<Fragment key={attribute.key}>
235-
{i > (groupLevel - joinLevel) && (
236-
<div className={styles.separator} />
237-
)}
238-
<div>{currentLabel}</div>
239-
</Fragment>
240-
);
241-
})}
242-
</h4>
243-
);
257+
return null;
244258
}
245259

246260
const taskDetails = taskById?.[groupedItem.value.task];
247-
248261
if (!taskDetails) {
249262
return null;
250263
}
251264

252265
return (
253-
<div className={styles.workItemContainer}>
254-
<Indent level={groupedItem.level - joinLevel} />
266+
<div
267+
className={styles.workItemContainer}
268+
key={groupedItem.value.clientId}
269+
>
270+
{indent && (
271+
<Indent
272+
level={groupedItem.level - joinLevel + 1}
273+
/>
274+
)}
255275
<WorkItemRow
256-
key={groupedItem.value.clientId}
257276
className={styles.workItem}
258277
workItem={groupedItem.value}
259278
onClone={onWorkItemClone}

src/views/DailyJournal/StartSidebar/index.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ import {
3737
numericOptions,
3838
} from '#utils/constants';
3939
import {
40+
DailyJournalAttribute,
4041
DailyJournalAttributeKeys,
41-
DailyJournalAttributeOrder,
4242
DailyJournalGrouping,
4343
} from '#utils/types';
4444

@@ -53,7 +53,7 @@ const dailyJournalAttributeDetails: Record<DailyJournalAttributeKeys, { label: s
5353

5454
interface ItemProps {
5555
className?: string;
56-
attribute: DailyJournalAttributeOrder;
56+
attribute: DailyJournalAttribute;
5757
setNodeRef?: (node: HTMLElement | null) => void;
5858
draggableAttributes?: DraggableAttributes;
5959
draggableListeners?: SyntheticListenerMap | undefined;
@@ -99,7 +99,7 @@ function Item(props: ItemProps) {
9999

100100
interface SortableItemProps {
101101
className?: string;
102-
attribute: DailyJournalAttributeOrder;
102+
attribute: DailyJournalAttribute;
103103
}
104104

105105
function SortableItem(props: SortableItemProps) {
@@ -247,7 +247,10 @@ function StartSidebar(props: Props) {
247247
strategy={verticalListSortingStrategy}
248248
>
249249
{storedConfig.dailyJournalAttributeOrder.map((attribute) => (
250-
<SortableItem attribute={attribute} />
250+
<SortableItem
251+
key={attribute.key}
252+
attribute={attribute}
253+
/>
251254
))}
252255
</SortableContext>
253256
</DndContext>

src/views/DailyJournal/index.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,24 @@ const MY_TIME_ENTRIES_QUERY = gql`
103103
}
104104
`;
105105

106+
/*
107+
query MyQuery {
108+
private {
109+
allTimeEntries(filters: {statuses: TODO, users: "9"}) {
110+
clientId
111+
id
112+
description
113+
date
114+
startTime
115+
duration
116+
status
117+
taskId
118+
type
119+
}
120+
}
121+
}
122+
*/
123+
106124
const BULK_TIME_ENTRY_MUTATION = gql`
107125
mutation BulkTimeEntry($timeEntries: [TimeEntryBulkCreateInput!], $deleteIds: [ID!]) {
108126
private {

0 commit comments

Comments
 (0)