Skip to content

Commit

Permalink
WIP - add an Imaging order button beneath usual Add to button on …
Browse files Browse the repository at this point in the history
…`grid-original` and render this new type of payload, with 'request type' dropdown etc.
  • Loading branch information
twrichards committed Dec 14, 2022
1 parent 7422c9e commit 3bf6347
Show file tree
Hide file tree
Showing 12 changed files with 206 additions and 20 deletions.
49 changes: 49 additions & 0 deletions client/src/addToPinboardButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import { textSans } from "../fontNormaliser";
import root from "react-shadow/emotion";
import * as Sentry from "@sentry/react";
import { TelemetryContext, PINBOARD_TELEMETRY_TYPE } from "./types/Telemetry";
import {
IMAGINE_REQUEST_TYPES,
IMAGING_REQUEST_ITEM_TYPE,
} from "../../shared/octopusImaging";

export const ASSET_HANDLE_HTML_TAG = "asset-handle";

Expand Down Expand Up @@ -80,6 +84,51 @@ const AddToPinboardButton = (props: AddToPinboardButtonProps) => {
`}
/>{" "}
</button>
{payloadToBeSent.type === "grid-original" && (
<button
onClick={() => {
props.setPayloadToBeSent({
type: IMAGING_REQUEST_ITEM_TYPE,
payload: {
...payloadToBeSent.payload,
requestType: IMAGINE_REQUEST_TYPES[0],
},
});
props.expand();
sendTelemetryEvent?.(
PINBOARD_TELEMETRY_TYPE.IMAGING_REQUEST_VIA_BUTTON,
{
assetType: IMAGING_REQUEST_ITEM_TYPE,
}
);
}}
css={css`
display: flex;
align-items: center;
margin-top: ${space[1]}px;
background-color: ${pinboard[500]};
${textSans.xsmall()};
border: none;
border-radius: 100px;
padding: 0 ${space[2]}px 0 ${space[3]}px;
line-height: 2;
cursor: pointer;
color: ${pinMetal};
`}
>
Imaging order
<PinIcon
css={css`
height: 18px;
margin-left: ${space[1]}px;
path {
stroke: ${pinMetal};
stroke-width: 1px;
}
`}
/>{" "}
</button>
)}
</root.div>
);
};
Expand Down
3 changes: 1 addition & 2 deletions client/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ export const PinBoardApp = ({ apolloClient, userEmail }: PinBoardAppProps) => {
const [payloadToBeSent, setPayloadToBeSent] = useState<PayloadAndType | null>(
null
);
const clearPayloadToBeSent = () => setPayloadToBeSent(null);

const [assetHandles, setAssetHandles] = useState<HTMLElement[]>([]);
const [workflowPinboardElements, setWorkflowPinboardElements] = useState<
Expand Down Expand Up @@ -371,7 +370,7 @@ export const PinBoardApp = ({ apolloClient, userEmail }: PinBoardAppProps) => {
openPinboardIdBasedOnQueryParam={openPinboardIdBasedOnQueryParam}
preselectedComposerId={preSelectedComposerId}
payloadToBeSent={payloadToBeSent}
clearPayloadToBeSent={clearPayloadToBeSent}
setPayloadToBeSent={setPayloadToBeSent}
isExpanded={isExpanded}
setIsExpanded={setIsExpanded}
userLookup={userLookup}
Expand Down
7 changes: 6 additions & 1 deletion client/src/createItemInputBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { gqlSearchMentionableUsers } from "../gql";
import { SvgSpinner } from "@guardian/source-react-components";
import { isGroup, isUser } from "../../shared/graphql/extraTypes";
import { groupToMentionHandle, userToMentionHandle } from "./mentionsUtil";
import { IMAGING_REQUEST_ITEM_TYPE } from "../../shared/octopusImaging";

interface WithEntity<E> {
entity: E & {
Expand Down Expand Up @@ -197,7 +198,11 @@ export const CreateItemInputBox = ({
onKeyPress={(event) => {
event.stopPropagation();
if (isEnterKey(event)) {
if (message || payloadToBeSent) {
if (
payloadToBeSent?.type === IMAGING_REQUEST_ITEM_TYPE
? message
: message || payloadToBeSent
) {
sendItem();
}
event.preventDefault();
Expand Down
8 changes: 4 additions & 4 deletions client/src/globalState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ interface GlobalStateContextShape {
activePinboards: PinboardData[];

payloadToBeSent: PayloadAndType | null;
clearPayloadToBeSent: () => void;
setPayloadToBeSent: (newPayload: PayloadAndType | null) => void;

addManuallyOpenedPinboardId: (
pinboardId: string,
Expand Down Expand Up @@ -102,7 +102,7 @@ interface GlobalStateProviderProps {
openPinboardIdBasedOnQueryParam: string | null;
preselectedComposerId: string | null | undefined;
payloadToBeSent: PayloadAndType | null;
clearPayloadToBeSent: () => void;
setPayloadToBeSent: (newPayload: PayloadAndType | null) => void;
isExpanded: boolean;
setIsExpanded: (_: boolean) => void;
userLookup: UserLookup;
Expand All @@ -120,7 +120,7 @@ export const GlobalStateProvider: React.FC<GlobalStateProviderProps> = ({
preselectedComposerId,
presetUnreadNotificationCount,
payloadToBeSent,
clearPayloadToBeSent,
setPayloadToBeSent,
isExpanded,
setIsExpanded,
userLookup,
Expand Down Expand Up @@ -496,7 +496,7 @@ export const GlobalStateProvider: React.FC<GlobalStateProviderProps> = ({
activePinboardIds,

payloadToBeSent,
clearPayloadToBeSent,
setPayloadToBeSent,

addManuallyOpenedPinboardId,
openPinboard,
Expand Down
83 changes: 83 additions & 0 deletions client/src/grid/octopusImagingOrderDisplay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { css } from "@emotion/react";
import React from "react";
import { ImagingOrderPayload } from "../types/PayloadAndType";
import {
IMAGINE_REQUEST_TYPES,
IMAGING_REQUEST_ITEM_TYPE,
ImagingRequestType,
} from "../../../shared/octopusImaging";
import { agateSans } from "../../fontNormaliser";
import { useGlobalStateContext } from "../globalState";
import { space } from "@guardian/source-foundations";

interface OctopusImagingOrderDisplayProps extends ImagingOrderPayload {
isEditable?: boolean;
}

export const OctopusImagingOrderDisplay = ({
payload,
isEditable,
}: OctopusImagingOrderDisplayProps) => {
const { setPayloadToBeSent } = useGlobalStateContext();
return (
<div
css={css`
${agateSans.xxsmall()}
`}
>
<h3
css={css`
margin: 0 0 ${space[1]}px;
`}
>
Imaging Order
</h3>
{isEditable && (
<div
css={css`
padding-right: 25px;
`}
>
<em>
{
"Don't forget to provide some notes to help Imaging team to understand your request"
}
</em>
</div>
)}
<img
src={payload.thumbnail}
css={css`
object-fit: contain;
width: 100%;
height: 100%;
`}
draggable={false}
// TODO: hover for larger thumbnail
/>
<div>
<strong>Request Type: </strong>
{isEditable ? (
<select
onClick={(e) => e.stopPropagation()}
onChange={(event) =>
setPayloadToBeSent({
type: IMAGING_REQUEST_ITEM_TYPE,
payload: {
...payload,
requestType: event.target.value as ImagingRequestType,
},
})
}
>
{IMAGINE_REQUEST_TYPES.map((requestType, index) => (
<option key={index}>{requestType}</option>
))}
</select>
) : (
payload.requestType
)}
</div>
</div>
);
};
24 changes: 18 additions & 6 deletions client/src/payloadDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import { SvgCross } from "@guardian/source-react-components";
import { buttonBackground } from "./styling";
import { GridStaticImageDisplay } from "./grid/gridStaticImageDisplay";
import { GridDynamicSearchDisplay } from "./grid/gridDynamicSearchDisplay";
import { TelemetryContext, PINBOARD_TELEMETRY_TYPE } from "./types/Telemetry";
import { PINBOARD_TELEMETRY_TYPE, TelemetryContext } from "./types/Telemetry";
import { Tab } from "./types/Tab";
import { IMAGING_REQUEST_ITEM_TYPE } from "../../shared/octopusImaging";
import { OctopusImagingOrderDisplay } from "./grid/octopusImagingOrderDisplay";

interface PayloadDisplayProps {
payloadAndType: PayloadAndType;
Expand All @@ -20,7 +22,6 @@ export const PayloadDisplay = ({
clearPayloadToBeSent,
tab,
}: PayloadDisplayProps) => {
const { payload } = payloadAndType;
const sendTelemetryEvent = useContext(TelemetryContext);
return (
<div
Expand Down Expand Up @@ -48,21 +49,24 @@ export const PayloadDisplay = ({
`}
draggable
onDragStart={(event) => {
event.dataTransfer.setData("URL", payload.embeddableUrl);
event.dataTransfer.setData(
"URL",
payloadAndType.payload.embeddableUrl
);
event.dataTransfer.setData(
// prevent grid from accepting these as drops, as per https://github.com/guardian/grid/commit/4b72d93eedcbacb4f90680764d468781a72507f5#diff-771b9da876348ce4b4e057e2d8253324c30a8f3db4e434d49b3ce70dbbdb0775R138-R140
"application/vnd.mediaservice.kahuna.image",
"true"
);
sendTelemetryEvent?.(PINBOARD_TELEMETRY_TYPE.DRAG_FROM_PINBOARD, {
assetType: payloadAndType?.type,
assetType: payloadAndType.type,
...(tab && { tab }),
});
}}
onClick={() => {
window.open(payload.embeddableUrl, "_blank");
window.open(payloadAndType.payload.embeddableUrl, "_blank");
sendTelemetryEvent?.(PINBOARD_TELEMETRY_TYPE.GRID_ASSET_OPENED, {
assetType: payloadAndType?.type,
assetType: payloadAndType.type,
tab: tab as Tab,
});
}}
Expand All @@ -79,6 +83,14 @@ export const PayloadDisplay = ({
<GridDynamicSearchDisplay payload={payloadAndType.payload} />
)}

{payloadAndType.type === IMAGING_REQUEST_ITEM_TYPE && (
<OctopusImagingOrderDisplay
type={payloadAndType.type}
payload={payloadAndType.payload}
isEditable={!!clearPayloadToBeSent}
/>
)}

{clearPayloadToBeSent && (
<div
css={css`
Expand Down
4 changes: 2 additions & 2 deletions client/src/pinboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export const Pinboard: React.FC<PinboardProps> = ({
addEmailsToLookup,

payloadToBeSent,
clearPayloadToBeSent,
setPayloadToBeSent,

showNotification,

Expand Down Expand Up @@ -363,7 +363,7 @@ export const Pinboard: React.FC<PinboardProps> = ({
<SendMessageArea
onSuccessfulSend={onSuccessfulSend}
payloadToBeSent={payloadToBeSent}
clearPayloadToBeSent={clearPayloadToBeSent}
clearPayloadToBeSent={() => setPayloadToBeSent(null)}
onError={(error) => setError(pinboardId, error)}
userEmail={userEmail}
pinboardId={pinboardId}
Expand Down
4 changes: 2 additions & 2 deletions client/src/selectPinboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export const SelectPinboard = ({
activePinboards,
activePinboardIds,
payloadToBeSent,
clearPayloadToBeSent,
setPayloadToBeSent,

isExpanded,

Expand Down Expand Up @@ -370,7 +370,7 @@ export const SelectPinboard = ({

<PayloadDisplay
payloadAndType={payloadToBeSent}
clearPayloadToBeSent={clearPayloadToBeSent}
clearPayloadToBeSent={() => setPayloadToBeSent(null)}
/>
</div>
)}
Expand Down
7 changes: 6 additions & 1 deletion client/src/sendMessageArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { SvgSpinner } from "@guardian/source-react-components";
import { isGroup, isUser } from "../../shared/graphql/extraTypes";
import { useConfirmModal } from "./modal";
import { groupToMentionHandle, userToMentionHandle } from "./mentionsUtil";
import { IMAGING_REQUEST_ITEM_TYPE } from "../../shared/octopusImaging";

interface SendMessageAreaProps {
payloadToBeSent: PayloadAndType | null;
Expand Down Expand Up @@ -178,7 +179,11 @@ export const SendMessageArea = ({
}
`}
onClick={sendItem}
disabled={isItemSending || !(message || payloadToBeSent)}
disabled={
isItemSending ||
!(message || payloadToBeSent) ||
(payloadToBeSent?.type === IMAGING_REQUEST_ITEM_TYPE && !message)
}
>
{isItemSending ? (
<SvgSpinner />
Expand Down
24 changes: 22 additions & 2 deletions client/src/types/PayloadAndType.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import {
IMAGING_REQUEST_ITEM_TYPE,
ImagingOrderPayloadFields,
} from "../../../shared/octopusImaging";

export const sources = ["grid"] as const;
export const sourceTypes = ["crop", "original", "search"] as const;

Expand All @@ -8,10 +13,15 @@ export type SourceType = typeof sourceTypes[number];
export const isSourceType = (sourceType: unknown): sourceType is SourceType =>
sourceTypes.includes(sourceType as SourceType);

export type PayloadType = `${Source}-${SourceType}`;
export type PayloadType =
| `${Source}-${SourceType}`
| typeof IMAGING_REQUEST_ITEM_TYPE;
export const isPayloadType = (
payloadType: string
): payloadType is PayloadType => {
if (payloadType === IMAGING_REQUEST_ITEM_TYPE) {
return true;
}
const parts = payloadType.split("-");
return parts.length === 2 && isSource(parts[0]) && isSourceType(parts[1]);
};
Expand Down Expand Up @@ -48,7 +58,15 @@ export type DynamicGridPayload = {
payload: PayloadWithApiUrl;
};

export type PayloadAndType = StaticGridPayload | DynamicGridPayload;
export type ImagingOrderPayload = {
type: typeof IMAGING_REQUEST_ITEM_TYPE;
payload: PayloadWithThumbnail & ImagingOrderPayloadFields;
};

export type PayloadAndType =
| StaticGridPayload
| DynamicGridPayload
| ImagingOrderPayload;

export const buildPayloadAndType = (
type: string,
Expand All @@ -63,5 +81,7 @@ export const buildPayloadAndType = (
"thumbnail" in payload
) {
return { type, payload };
} else if (type === IMAGING_REQUEST_ITEM_TYPE && "requestType" in payload) {
return { type, payload };
}
};
Loading

0 comments on commit 3bf6347

Please sign in to comment.