diff --git a/bootstrapping-lambda/local/index.html b/bootstrapping-lambda/local/index.html index 23aa3dda..c7d318c7 100644 --- a/bootstrapping-lambda/local/index.html +++ b/bootstrapping-lambda/local/index.html @@ -38,7 +38,7 @@

Remove pinboard pre-selection -

Starred messages
+
Starred messages (requires pinboard pre-selection)

via hidden element (for invalid/untracked composer ID)

diff --git a/client/src/formattedDateTime.tsx b/client/src/formattedDateTime.tsx index 74180a19..9e9d3b14 100644 --- a/client/src/formattedDateTime.tsx +++ b/client/src/formattedDateTime.tsx @@ -4,7 +4,7 @@ import { formatDateTime } from "./util"; export const TickContext = React.createContext(Date.now()); interface FormattedDateTimeProps { - timestamp: number; + timestamp: number | string; isPartOfSentence?: true; withAgo?: true; } diff --git a/client/src/itemDisplay.tsx b/client/src/itemDisplay.tsx index 17184101..e4612423 100644 --- a/client/src/itemDisplay.tsx +++ b/client/src/itemDisplay.tsx @@ -78,8 +78,6 @@ export const ItemDisplay = ({ [item.id, item.message] ); - const dateInMillisecs = new Date(item.timestamp).valueOf(); - const isDifferentUserFromPreviousItem = maybePreviousItem?.userEmail !== item.userEmail; @@ -172,7 +170,7 @@ export const ItemDisplay = ({ margin-bottom: 2px; `} > - + {isEdited &&  - Edited} {maybeRelatedItem && item.type !== "claim" && (  - Reply diff --git a/client/src/nestedItemDisplay.tsx b/client/src/nestedItemDisplay.tsx index 13362a23..a68933c0 100644 --- a/client/src/nestedItemDisplay.tsx +++ b/client/src/nestedItemDisplay.tsx @@ -103,7 +103,7 @@ export const NestedItemDisplay = ({ margin-left: ${payloadAndType ? 0 : 10}px; `} > - + {item.editHistory && item.editHistory.length > 0 && ( - Edited )} diff --git a/client/src/pinboard.tsx b/client/src/pinboard.tsx index ea9206ac..a29e2b3d 100644 --- a/client/src/pinboard.tsx +++ b/client/src/pinboard.tsx @@ -400,7 +400,11 @@ export const Pinboard: React.FC = ({ {isPinboardData(preselectedPinboard) && preselectedPinboard.id === pinboardId && maybeStarredMessagesArea && ( - + )} ); diff --git a/client/src/starred/starredMessages.tsx b/client/src/starred/starredMessages.tsx index 4235a230..0574b552 100644 --- a/client/src/starred/starredMessages.tsx +++ b/client/src/starred/starredMessages.tsx @@ -1,19 +1,73 @@ import React from "react"; import ReactDOM from "react-dom"; +import { Item } from "shared/graphql/graphql"; +import root from "react-shadow/emotion"; +import { UserLookup } from "../types/UserLookup"; +import { FormattedDateTime } from "../formattedDateTime"; +import { css } from "@emotion/react"; +import { agateSans } from "../../fontNormaliser"; +import { neutral, space } from "@guardian/source-foundations"; export const STARRED_MESSAGES_HTML_TAG = "pinboard-starred-messages"; -// interface StarredMessagesProps {} +const StarredItemDisplay = ({ + item, + userLookup, +}: { + item: Item; + userLookup: UserLookup; +}) => { + const user = userLookup[item.userEmail]; + return ( +
+ + {item.message} + + + {user.firstName} {user.lastName} + + + + +
+ ); +}; -const StarredMessages = (/* props: StarredMessagesProps */) => ( -
-

Starred Messages

-
-); +interface StarredMessagesProps { + items: Item[]; + userLookup: UserLookup; +} + +const StarredMessages = ({ items, userLookup }: StarredMessagesProps) => { + const starredMessages = items.filter((item) => item.isStarred); + return ( + + {starredMessages.map((item) => ( + + ))} + + ); +}; -interface StarredMessagesPortalProps { +interface StarredMessagesPortalProps extends StarredMessagesProps { node: Element; } -export const StarredMessagesPortal = ({ node }: StarredMessagesPortalProps) => - ReactDOM.createPortal(, node); +export const StarredMessagesPortal = ({ + node, + ...props +}: StarredMessagesPortalProps) => + ReactDOM.createPortal(, node); diff --git a/client/src/util.ts b/client/src/util.ts index 2650e8e8..87db7be2 100644 --- a/client/src/util.ts +++ b/client/src/util.ts @@ -13,11 +13,15 @@ export const getTooltipText = ( ) => `WT: ${workingTitle}` + (headline ? `\nHL: ${headline}` : ""); export const formatDateTime = ( - timestamp: number, - isPartOfSentence?: true, - withAgo?: true + timestampStringOrEpochMillis: number | string, + isPartOfSentence?: boolean, + withAgo?: boolean ): string => { const now = Date.now(); + const timestamp = + typeof timestampStringOrEpochMillis === "string" + ? new Date(timestampStringOrEpochMillis).valueOf() + : timestampStringOrEpochMillis; if (isThisYear(timestamp)) { if (isToday(timestamp)) { if (differenceInMinutes(now, timestamp) < 1) { @@ -32,7 +36,7 @@ export const formatDateTime = ( return ( formatDistanceStrict(timestamp, now, { roundingMethod: "floor", - }).slice(0, -4) + (withAgo ? " ago" : "") + }).slice(0, -4) + (withAgo ? "s ago" : "") ); } return format(timestamp, "HH:mm"); diff --git a/client/test/formattedDateTime.test.ts b/client/test/formattedDateTime.test.ts index 0592f1e4..a1711bda 100644 --- a/client/test/formattedDateTime.test.ts +++ b/client/test/formattedDateTime.test.ts @@ -28,6 +28,13 @@ test("display is correct if timestamp is between 2 min and 1 hr ago", () => { expect(formatDateTime(twoMinsAgo)).toBe("2 min"); const lessThanHr = subMinutes(Date.now(), 59).valueOf(); expect(formatDateTime(lessThanHr)).toBe("59 min"); + const pluralMinsWithAgo = subMinutes(Date.now(), 3).valueOf(); + expect(formatDateTime(pluralMinsWithAgo, false, true)).toBe("3 mins ago"); +}); + +test("display is correct if passed a string", () => { + const twoMinsAgoString = subMinutes(Date.now(), 2).toISOString(); + expect(formatDateTime(twoMinsAgoString)).toBe("2 min"); }); test("display is correct if timestamp is 1 hr ago exactly", () => {