Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/App/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const ME_QUERY = gql`
id
lastName
isStaff
loginExpire
}
}
}
Expand Down
52 changes: 0 additions & 52 deletions src/components/Clock/index.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion src/components/Navbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ function Navbar(props: Props) {
{isNotDefined(userAuth) && (
<Link
external
href={`${import.meta.env.APP_GRAPHQL_DOMAIN}/dev/sign_in/?redirect_to=${window.location.href}`}
href={`${import.meta.env.APP_GRAPHQL_DOMAIN}/?redirect_to=${window.location.href}`}
>
Login
</Link>
Expand Down
100 changes: 100 additions & 0 deletions src/components/StandupConductors/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import {
_cs,
encodeDate,
} from '@togglecorp/fujs';
import {
gql,
useQuery,
} from 'urql';

import DisplayPicture from '#components/DisplayPicture';
import TextOutput from '#components/TextOutput';
import {
type StandupConductorsQuery,
type StandupConductorsQueryVariables,
} from '#generated/types/graphql';

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

const STANDUP_CONDUCTORS = gql`
query StandupConductors($date: Date!){
private {
dailyStandup(date: $date) {
conductor {
id
displayName
displayPicture
}
fallbackConductor {
id
displayName
displayPicture
}
}
}
}
`;

const todayDate = encodeDate(new Date());

function StandupConductors() {
const [conductorsResponse] = useQuery<StandupConductorsQuery, StandupConductorsQueryVariables>({
query: STANDUP_CONDUCTORS,
variables: { date: todayDate },
requestPolicy: 'cache-and-network',
});

const standupConductors = conductorsResponse.data?.private.dailyStandup;

return (
<div className={styles.conductors}>
<TextOutput
className={_cs(
styles.conductorItem,
!standupConductors && styles.hidden,
)}
label="Standup Lead"
valueContainerClassName={styles.conductorValue}
value={(
<>
<DisplayPicture
imageUrl={standupConductors?.conductor?.displayPicture}
displayName={standupConductors?.conductor?.displayName ?? 'Anonymous'}
/>
<span>
{standupConductors?.conductor?.displayName
?? 'Anonymous'}
</span>
</>
)}
block
hideLabelColon
/>
<TextOutput
className={_cs(
styles.conductorItem,
!standupConductors && styles.hidden,
)}
label="Acting Lead"
valueContainerClassName={styles.conductorValue}
value={(
<>
<DisplayPicture
imageUrl={standupConductors
?.fallbackConductor?.displayPicture}
displayName={standupConductors?.fallbackConductor?.displayName ?? 'Anonymous'}
/>
<span>
{standupConductors?.fallbackConductor?.displayName
?? 'Anonymous'}
</span>
</>
)}
block
hideLabelColon
/>
</div>
);
}

export default StandupConductors;
24 changes: 24 additions & 0 deletions src/components/StandupConductors/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.conductors {
display: flex;
flex-direction: column;
gap: var(--spacing-md);

.conductor-item {
display: flex;
justify-content: center;
gap: var(--spacing-xs);

&.hidden {
visibility: hidden;
}

.conductor-value {
display: flex;
align-items: center;
justify-content: center;
font-size: var(--font-size-lg);
font-weight: var(--font-weight-normal);
gap: var(--spacing-xs);
}
}
}
60 changes: 60 additions & 0 deletions src/components/TextOutput/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React from 'react';
import { _cs } from '@togglecorp/fujs';

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

interface Props {
className?: string;
label?: React.ReactNode;
labelContainerClassName?: string;
description?: React.ReactNode;
descriptionContainerClassName?: string;
valueContainerClassName?: string;
hideLabelColon?: boolean;
block?: boolean;
value?: React.ReactNode;
}

function TextOutput(props: Props) {
const {
className,
label,
labelContainerClassName,
valueContainerClassName,
description,
descriptionContainerClassName,
hideLabelColon,
block,
value,
} = props;

return (
<div
className={_cs(
styles.textOutput,
!hideLabelColon && styles.withLabelColon,
// NOTE:
// styles.blok is supposed to be styles.block
// but we encountered a strange behavior
block && styles.blok,
className,
)}
>
{label && (
<div className={_cs(styles.label, labelContainerClassName)}>
{label}
</div>
)}
<div className={_cs(styles.value, valueContainerClassName)}>
{value}
</div>
{description && (
<div className={_cs(styles.description, descriptionContainerClassName)}>
{description}
</div>
)}
</div>
);
}

export default TextOutput;
37 changes: 37 additions & 0 deletions src/components/TextOutput/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
.text-output {
--spacing: var(--spacing-md);
display: flex;
align-items: baseline;
font-size: var(--font-size-md);
gap: var(--spacing-sm);

&.blok {
align-items: initial;
flex-direction: column;
}

>.label {
color: var(--color-text);
}

>.value {
font-weight: var(--font-weight-bold);

/* Useful for nested text outputs */
.text-output {
font-weight: var(--font-weight-semibold);
}
}

>.description {
color: var(--color-text-light);
}

&.with-label-colon {
>.label {
&:after {
content: ':';
}
}
}
}
2 changes: 1 addition & 1 deletion src/contexts/user.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { UserMeType } from '#generated/types/graphql';

export type UserAuth = Pick<
UserMeType,
'displayName' | 'displayPicture' | 'email' | 'firstName' | 'id' | 'lastName' | 'isStaff'
'displayName' | 'displayPicture' | 'email' | 'firstName' | 'id' | 'lastName' | 'isStaff' | 'loginExpire'
>;

export interface UserContextProps {
Expand Down
30 changes: 30 additions & 0 deletions src/hooks/useCurrentDate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {
useEffect,
useState,
} from 'react';

function useCurrentDate() {
const [dateStr, setDateStr] = useState(() => {
const date = new Date();
return date;
});

useEffect(
() => {
const timeout = window.setInterval(
() => {
const date = new Date();
setDateStr(date);
},
5000,
);
return () => {
window.clearInterval(timeout);
};
},
[],
);
return dateStr;
}

export default useCurrentDate;
18 changes: 18 additions & 0 deletions src/utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -395,3 +395,21 @@ export function putUndefined<T extends object>(value: T) {

return copy as PutUndefined<T>;
}

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

export function formatDateTime(date: Date) {
return dateTimeFormatter.format(date);
}
12 changes: 10 additions & 2 deletions src/views/DailyStandup/DeadlineSection/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ import {
useQuery,
} from 'urql';

import Clock from '#components/Clock';
import StandupConductors from '#components/StandupConductors';
import {
type DeadlinesAndEventsQuery,
type DeadlinesAndEventsQueryVariables,
} from '#generated/types/graphql';
import useCurrentDate from '#hooks/useCurrentDate';
import { formatDateTime } from '#utils/common';
import { type GeneralEvent } from '#utils/types';

import Slide from '../Slide';
Expand Down Expand Up @@ -97,13 +99,19 @@ function DeadlineSection() {
})) ?? []),
].sort((a, b) => compareNumber(a.remainingDays, b.remainingDays));
}, [events, projects]);
const todayDate = useCurrentDate();

return (
<Slide
variant="split"
primaryPreText="Welcome to"
primaryHeading="Daily Standup"
primaryDescription={<Clock />}
primaryDescription={(
<div className={styles.primarySection}>
<div>{formatDateTime(todayDate)}</div>
<StandupConductors />
</div>
)}
secondaryHeading="Upcoming Events"
secondaryContent={upcomingEvents.map(
(generalEvent, index) => (
Expand Down
Loading