Skip to content

Commit

Permalink
Add icon support on group titles
Browse files Browse the repository at this point in the history
- Add clock on daily standup
- Use human friendly date format on monthly calendar
- Better UX for the availability dialog
    - Show disabled options instead of no option
- Only show availability of un-available users
  • Loading branch information
tnagorra committed Oct 16, 2024
1 parent b5394cf commit fb641e8
Show file tree
Hide file tree
Showing 11 changed files with 164 additions and 95 deletions.
52 changes: 52 additions & 0 deletions src/components/Clock/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import {
useEffect,
useState,
} from 'react';

const dateTimeFormatter = new Intl.DateTimeFormat(
[],
{
year: 'numeric',
month: 'short',
day: 'numeric',
weekday: 'short',
hour: 'numeric',
minute: 'numeric',
// second: 'numeric',
hour12: true,
},
);

function formatTime(date: Date) {
return dateTimeFormatter.format(date);
}

function Clock() {
const [dateStr, setDateStr] = useState(() => {
const date = new Date();
return formatTime(date);
});
useEffect(
() => {
const timeout = window.setInterval(
() => {
const date = new Date();
const dateAsString = formatTime(date);
setDateStr(dateAsString);
},
500,
);
return () => {
window.clearInterval(timeout);
};
},
[],
);
return (
<div>
{dateStr}
</div>
);
}

export default Clock;
15 changes: 12 additions & 3 deletions src/components/MonthlyCalendar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ import DateContext from '#contexts/date';

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

const dateFormatter = new Intl.DateTimeFormat(
[],
{
year: 'numeric',
month: 'short',
},
);

const weekDaysName = [
'Su',
'Mo',
Expand Down Expand Up @@ -129,6 +137,8 @@ function MonthlyCalendar(props: Props) {
return days;
}, [year, month]);

const formattedDate = dateFormatter.format(new Date(year, month, 1));

return (
<div className={_cs(styles.calendarContainer, className)}>
<div className={styles.header}>
Expand All @@ -150,10 +160,9 @@ function MonthlyCalendar(props: Props) {
>
<RiArrowRightSLine />
</Button>
<div className={styles.spacer} />
<div>
{year}
/
{String(month + 1).padStart(2, '0')}
{formattedDate}
</div>
</div>
<div className={styles.monthlyCalendar}>
Expand Down
4 changes: 4 additions & 0 deletions src/components/MonthlyCalendar/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
gap: var(--spacing-sm);
align-items: baseline;
font-size: var(--font-size-sm);

.spacer {
flex-grow: 1;
}
}

.monthly-calendar {
Expand Down
54 changes: 26 additions & 28 deletions src/views/DailyJournal/AvailabilityDialog/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ function AvailabilityDialog(props: Props) {
return key === 'FIRST_HALF';
}
if (dialogState.wfhType === 'FULL') {
return false;
// NOTE: So that we can see all options
return true;
}
return true;
},
Expand All @@ -204,7 +205,8 @@ function AvailabilityDialog(props: Props) {
return key === 'FIRST_HALF';
}
if (dialogState.leaveType === 'FULL') {
return false;
// NOTE: So that we can see all options
return true;
}
return true;
},
Expand All @@ -221,32 +223,28 @@ function AvailabilityDialog(props: Props) {
contentClassName={styles.modalContent}
className={styles.availabilityDialog}
>
{dialogState.wfhType !== 'FULL' && (
<RadioInput
name="leaveType"
label="Leave"
options={availableLeaveTypeOptions}
keySelector={leaveTypeKeySelector}
labelSelector={leaveTypeLabelSelector}
onChange={setFieldValue}
value={dialogState.leaveType}
disabled={disabled}
clearable
/>
)}
{dialogState.leaveType !== 'FULL' && (
<RadioInput
name="wfhType"
label="Work from home"
options={availableWfhTypeOptions}
keySelector={wfhTypeKeySelector}
labelSelector={wfhTypeLabelSelector}
onChange={setFieldValue}
value={dialogState.wfhType}
disabled={disabled}
clearable
/>
)}
<RadioInput
name="leaveType"
label="Leave"
options={availableLeaveTypeOptions}
keySelector={leaveTypeKeySelector}
labelSelector={leaveTypeLabelSelector}
onChange={setFieldValue}
value={dialogState.leaveType}
disabled={disabled || dialogState.wfhType === 'FULL'}
clearable
/>
<RadioInput
name="wfhType"
label="Work from home"
options={availableWfhTypeOptions}
keySelector={wfhTypeKeySelector}
labelSelector={wfhTypeLabelSelector}
onChange={setFieldValue}
value={dialogState.wfhType}
disabled={disabled || dialogState.leaveType === 'FULL'}
clearable
/>
<div className={styles.actions}>
<Button
title="Cancel update availability"
Expand Down
39 changes: 39 additions & 0 deletions src/views/DailyJournal/DayView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,23 @@ function DayView(props: Props) {
return undefined;
}, [taskById]);

const getWorkItemIconFromAttr = useCallback((
item: WorkItem,
attr: DailyJournalAttribute,
) => {
if (isNotDefined(taskById)) {
return undefined;
}

const taskDetails = taskById[item.task];

if (attr.key === 'project') {
return taskDetails.contract.project.logo;
}

return undefined;
}, [taskById]);

const formattedDate = dateFormatter.format(new Date(selectedDate));
const formattedRelativeDate = useFormattedRelativeDate(selectedDate);

Expand Down Expand Up @@ -199,6 +216,10 @@ function DayView(props: Props) {
groupedItem.value,
groupedItem.attribute,
);
const currentIcon = getWorkItemIconFromAttr(
groupedItem.value,
groupedItem.attribute,
);

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

Expand All @@ -208,6 +229,13 @@ function DayView(props: Props) {
className={styles.nestedHeading}
>
{indent && <Indent level={groupedItem.level} />}
{currentIcon && (
<img
className={styles.icon}
src={currentIcon.url}
alt={headingText}
/>
)}
{headingText}
</Heading>
);
Expand Down Expand Up @@ -236,6 +264,10 @@ function DayView(props: Props) {
groupedItem.value,
attribute,
);
const currentIcon = getWorkItemIconFromAttr(
groupedItem.value,
attribute,
);

if (i < (groupLevel - joinLevel)) {
return null;
Expand All @@ -246,6 +278,13 @@ function DayView(props: Props) {
{i > (groupLevel - joinLevel) && (
<div className={styles.separator} />
)}
{currentIcon && (
<img
className={styles.icon}
src={currentIcon.url}
alt={currentLabel}
/>
)}
<div>{currentLabel}</div>
</Fragment>
);
Expand Down
8 changes: 8 additions & 0 deletions src/views/DailyJournal/DayView/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@

&h2 {
margin-top: var(--spacing-md);

.icon {
height: 1em;
}
}
}

Expand All @@ -76,6 +80,10 @@
width: 0.5rem;
height: 0.5rem;
}

.icon {
height: 1em;
}
}

.work-item-container {
Expand Down
3 changes: 1 addition & 2 deletions src/views/DailyJournal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import {
encodeDate,
isDefined,
isNotDefined,
isTruthyString,
} from '@togglecorp/fujs';
import {
gql,
Expand Down Expand Up @@ -751,7 +750,7 @@ export function Component() {
>
Add entry
</Button>
{!isTruthyString(dateFromParams) && (
{selectedDate !== fullDate && (
<Link
to="dailyJournal"
variant="quaternary"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
}

.days {
width: 5rem;
width: 6rem;
color: var(--color-text-light);
}
}
25 changes: 3 additions & 22 deletions src/views/DailyStandup/DeadlineSection/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
useQuery,
} from 'urql';

import Clock from '#components/Clock';
import {
type DeadlinesAndEventsQuery,
type DeadlinesAndEventsQueryVariables,
Expand All @@ -26,16 +27,6 @@ import GeneralEventOutput from './GeneralEvent';

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

const dateFormatter = new Intl.DateTimeFormat(
[],
{
year: 'numeric',
month: 'short',
day: 'numeric',
weekday: 'short',
},
);

const DEADLINES_AND_EVENTS = gql`
query DeadlinesAndEvents {
private {
Expand All @@ -60,15 +51,7 @@ const DEADLINES_AND_EVENTS = gql`
}
`;

interface Props {
date: string;
}

function DeadlineSection(props: Props) {
const {
date,
} = props;

function DeadlineSection() {
const [deadlinesAndEvents] = useQuery<
DeadlinesAndEventsQuery,
DeadlinesAndEventsQueryVariables
Expand All @@ -79,8 +62,6 @@ function DeadlineSection(props: Props) {
const projects = deadlinesAndEvents.data?.private.allProjects;
const events = deadlinesAndEvents.data?.private.relativeEvents;

const formattedDate = dateFormatter.format(new Date(date));

const upcomingEvents = useMemo<GeneralEvent[]>(() => {
const deadlines = projects?.flatMap(
(project) => project.deadlines.map((deadline) => ({
Expand Down Expand Up @@ -121,7 +102,7 @@ function DeadlineSection(props: Props) {
variant="split"
primaryPreText="Welcome to"
primaryHeading="Daily Standup"
primaryDescription={formattedDate}
primaryDescription={<Clock />}
secondaryHeading="Upcoming Events"
secondaryContent={upcomingEvents.map(
(generalEvent, index) => (
Expand Down
Loading

0 comments on commit fb641e8

Please sign in to comment.