Skip to content

Commit 24b5bb1

Browse files
authored
Merge pull request #9 from toggle-corp/feature/grouped-task-icons
Add icon support on group titles
2 parents b5394cf + fb641e8 commit 24b5bb1

File tree

11 files changed

+164
-95
lines changed

11 files changed

+164
-95
lines changed

src/components/Clock/index.tsx

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import {
2+
useEffect,
3+
useState,
4+
} from 'react';
5+
6+
const dateTimeFormatter = new Intl.DateTimeFormat(
7+
[],
8+
{
9+
year: 'numeric',
10+
month: 'short',
11+
day: 'numeric',
12+
weekday: 'short',
13+
hour: 'numeric',
14+
minute: 'numeric',
15+
// second: 'numeric',
16+
hour12: true,
17+
},
18+
);
19+
20+
function formatTime(date: Date) {
21+
return dateTimeFormatter.format(date);
22+
}
23+
24+
function Clock() {
25+
const [dateStr, setDateStr] = useState(() => {
26+
const date = new Date();
27+
return formatTime(date);
28+
});
29+
useEffect(
30+
() => {
31+
const timeout = window.setInterval(
32+
() => {
33+
const date = new Date();
34+
const dateAsString = formatTime(date);
35+
setDateStr(dateAsString);
36+
},
37+
500,
38+
);
39+
return () => {
40+
window.clearInterval(timeout);
41+
};
42+
},
43+
[],
44+
);
45+
return (
46+
<div>
47+
{dateStr}
48+
</div>
49+
);
50+
}
51+
52+
export default Clock;

src/components/MonthlyCalendar/index.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ import DateContext from '#contexts/date';
1919

2020
import styles from './styles.module.css';
2121

22+
const dateFormatter = new Intl.DateTimeFormat(
23+
[],
24+
{
25+
year: 'numeric',
26+
month: 'short',
27+
},
28+
);
29+
2230
const weekDaysName = [
2331
'Su',
2432
'Mo',
@@ -129,6 +137,8 @@ function MonthlyCalendar(props: Props) {
129137
return days;
130138
}, [year, month]);
131139

140+
const formattedDate = dateFormatter.format(new Date(year, month, 1));
141+
132142
return (
133143
<div className={_cs(styles.calendarContainer, className)}>
134144
<div className={styles.header}>
@@ -150,10 +160,9 @@ function MonthlyCalendar(props: Props) {
150160
>
151161
<RiArrowRightSLine />
152162
</Button>
163+
<div className={styles.spacer} />
153164
<div>
154-
{year}
155-
/
156-
{String(month + 1).padStart(2, '0')}
165+
{formattedDate}
157166
</div>
158167
</div>
159168
<div className={styles.monthlyCalendar}>

src/components/MonthlyCalendar/styles.module.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
gap: var(--spacing-sm);
99
align-items: baseline;
1010
font-size: var(--font-size-sm);
11+
12+
.spacer {
13+
flex-grow: 1;
14+
}
1115
}
1216

1317
.monthly-calendar {

src/views/DailyJournal/AvailabilityDialog/index.tsx

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,8 @@ function AvailabilityDialog(props: Props) {
188188
return key === 'FIRST_HALF';
189189
}
190190
if (dialogState.wfhType === 'FULL') {
191-
return false;
191+
// NOTE: So that we can see all options
192+
return true;
192193
}
193194
return true;
194195
},
@@ -204,7 +205,8 @@ function AvailabilityDialog(props: Props) {
204205
return key === 'FIRST_HALF';
205206
}
206207
if (dialogState.leaveType === 'FULL') {
207-
return false;
208+
// NOTE: So that we can see all options
209+
return true;
208210
}
209211
return true;
210212
},
@@ -221,32 +223,28 @@ function AvailabilityDialog(props: Props) {
221223
contentClassName={styles.modalContent}
222224
className={styles.availabilityDialog}
223225
>
224-
{dialogState.wfhType !== 'FULL' && (
225-
<RadioInput
226-
name="leaveType"
227-
label="Leave"
228-
options={availableLeaveTypeOptions}
229-
keySelector={leaveTypeKeySelector}
230-
labelSelector={leaveTypeLabelSelector}
231-
onChange={setFieldValue}
232-
value={dialogState.leaveType}
233-
disabled={disabled}
234-
clearable
235-
/>
236-
)}
237-
{dialogState.leaveType !== 'FULL' && (
238-
<RadioInput
239-
name="wfhType"
240-
label="Work from home"
241-
options={availableWfhTypeOptions}
242-
keySelector={wfhTypeKeySelector}
243-
labelSelector={wfhTypeLabelSelector}
244-
onChange={setFieldValue}
245-
value={dialogState.wfhType}
246-
disabled={disabled}
247-
clearable
248-
/>
249-
)}
226+
<RadioInput
227+
name="leaveType"
228+
label="Leave"
229+
options={availableLeaveTypeOptions}
230+
keySelector={leaveTypeKeySelector}
231+
labelSelector={leaveTypeLabelSelector}
232+
onChange={setFieldValue}
233+
value={dialogState.leaveType}
234+
disabled={disabled || dialogState.wfhType === 'FULL'}
235+
clearable
236+
/>
237+
<RadioInput
238+
name="wfhType"
239+
label="Work from home"
240+
options={availableWfhTypeOptions}
241+
keySelector={wfhTypeKeySelector}
242+
labelSelector={wfhTypeLabelSelector}
243+
onChange={setFieldValue}
244+
value={dialogState.wfhType}
245+
disabled={disabled || dialogState.leaveType === 'FULL'}
246+
clearable
247+
/>
250248
<div className={styles.actions}>
251249
<Button
252250
title="Cancel update availability"

src/views/DailyJournal/DayView/index.tsx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,23 @@ function DayView(props: Props) {
100100
return undefined;
101101
}, [taskById]);
102102

103+
const getWorkItemIconFromAttr = useCallback((
104+
item: WorkItem,
105+
attr: DailyJournalAttribute,
106+
) => {
107+
if (isNotDefined(taskById)) {
108+
return undefined;
109+
}
110+
111+
const taskDetails = taskById[item.task];
112+
113+
if (attr.key === 'project') {
114+
return taskDetails.contract.project.logo;
115+
}
116+
117+
return undefined;
118+
}, [taskById]);
119+
103120
const formattedDate = dateFormatter.format(new Date(selectedDate));
104121
const formattedRelativeDate = useFormattedRelativeDate(selectedDate);
105122

@@ -199,6 +216,10 @@ function DayView(props: Props) {
199216
groupedItem.value,
200217
groupedItem.attribute,
201218
);
219+
const currentIcon = getWorkItemIconFromAttr(
220+
groupedItem.value,
221+
groupedItem.attribute,
222+
);
202223

203224
const Heading = `h${bound(groupedItem.level + 2, 2, 4)}` as unknown as ElementType;
204225

@@ -208,6 +229,13 @@ function DayView(props: Props) {
208229
className={styles.nestedHeading}
209230
>
210231
{indent && <Indent level={groupedItem.level} />}
232+
{currentIcon && (
233+
<img
234+
className={styles.icon}
235+
src={currentIcon.url}
236+
alt={headingText}
237+
/>
238+
)}
211239
{headingText}
212240
</Heading>
213241
);
@@ -236,6 +264,10 @@ function DayView(props: Props) {
236264
groupedItem.value,
237265
attribute,
238266
);
267+
const currentIcon = getWorkItemIconFromAttr(
268+
groupedItem.value,
269+
attribute,
270+
);
239271

240272
if (i < (groupLevel - joinLevel)) {
241273
return null;
@@ -246,6 +278,13 @@ function DayView(props: Props) {
246278
{i > (groupLevel - joinLevel) && (
247279
<div className={styles.separator} />
248280
)}
281+
{currentIcon && (
282+
<img
283+
className={styles.icon}
284+
src={currentIcon.url}
285+
alt={currentLabel}
286+
/>
287+
)}
249288
<div>{currentLabel}</div>
250289
</Fragment>
251290
);

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@
6060

6161
&h2 {
6262
margin-top: var(--spacing-md);
63+
64+
.icon {
65+
height: 1em;
66+
}
6367
}
6468
}
6569

@@ -76,6 +80,10 @@
7680
width: 0.5rem;
7781
height: 0.5rem;
7882
}
83+
84+
.icon {
85+
height: 1em;
86+
}
7987
}
8088

8189
.work-item-container {

src/views/DailyJournal/index.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import {
2727
encodeDate,
2828
isDefined,
2929
isNotDefined,
30-
isTruthyString,
3130
} from '@togglecorp/fujs';
3231
import {
3332
gql,
@@ -751,7 +750,7 @@ export function Component() {
751750
>
752751
Add entry
753752
</Button>
754-
{!isTruthyString(dateFromParams) && (
753+
{selectedDate !== fullDate && (
755754
<Link
756755
to="dailyJournal"
757756
variant="quaternary"

src/views/DailyStandup/DeadlineSection/GeneralEvent/styles.module.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
}
88

99
.days {
10-
width: 5rem;
10+
width: 6rem;
1111
color: var(--color-text-light);
1212
}
1313
}

src/views/DailyStandup/DeadlineSection/index.tsx

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
useQuery,
1616
} from 'urql';
1717

18+
import Clock from '#components/Clock';
1819
import {
1920
type DeadlinesAndEventsQuery,
2021
type DeadlinesAndEventsQueryVariables,
@@ -26,16 +27,6 @@ import GeneralEventOutput from './GeneralEvent';
2627

2728
import styles from './styles.module.css';
2829

29-
const dateFormatter = new Intl.DateTimeFormat(
30-
[],
31-
{
32-
year: 'numeric',
33-
month: 'short',
34-
day: 'numeric',
35-
weekday: 'short',
36-
},
37-
);
38-
3930
const DEADLINES_AND_EVENTS = gql`
4031
query DeadlinesAndEvents {
4132
private {
@@ -60,15 +51,7 @@ const DEADLINES_AND_EVENTS = gql`
6051
}
6152
`;
6253

63-
interface Props {
64-
date: string;
65-
}
66-
67-
function DeadlineSection(props: Props) {
68-
const {
69-
date,
70-
} = props;
71-
54+
function DeadlineSection() {
7255
const [deadlinesAndEvents] = useQuery<
7356
DeadlinesAndEventsQuery,
7457
DeadlinesAndEventsQueryVariables
@@ -79,8 +62,6 @@ function DeadlineSection(props: Props) {
7962
const projects = deadlinesAndEvents.data?.private.allProjects;
8063
const events = deadlinesAndEvents.data?.private.relativeEvents;
8164

82-
const formattedDate = dateFormatter.format(new Date(date));
83-
8465
const upcomingEvents = useMemo<GeneralEvent[]>(() => {
8566
const deadlines = projects?.flatMap(
8667
(project) => project.deadlines.map((deadline) => ({
@@ -121,7 +102,7 @@ function DeadlineSection(props: Props) {
121102
variant="split"
122103
primaryPreText="Welcome to"
123104
primaryHeading="Daily Standup"
124-
primaryDescription={formattedDate}
105+
primaryDescription={<Clock />}
125106
secondaryHeading="Upcoming Events"
126107
secondaryContent={upcomingEvents.map(
127108
(generalEvent, index) => (

0 commit comments

Comments
 (0)