Skip to content

Commit

Permalink
add an Imaging order button beneath usual Add to button on `grid-…
Browse files Browse the repository at this point in the history
…original` and render this new type of payload, with 'request type' dropdown etc.
  • Loading branch information
twrichards committed May 23, 2024
1 parent dde62df commit 0d7dd60
Show file tree
Hide file tree
Showing 10 changed files with 198 additions and 16 deletions.
50 changes: 50 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,52 @@ 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};
white-space: nowrap; // TODO this is a hack to stop the button from wrapping, but we should think of wording that fits better
`}
>
Imaging order
<PinIcon
css={css`
height: 18px;
margin-left: ${space[1]}px;
path {
stroke: ${pinMetal};
stroke-width: 1px;
}
`}
/>{" "}
</button>
)}
</root.div>
);
};
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>
);
};
9 changes: 6 additions & 3 deletions client/src/itemInputBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { isGroup, isUser } from "shared/graphql/extraTypes";
import { groupToMentionHandle, userToMentionHandle } from "./mentionsUtil";
import { useTourProgress } from "./tour/tourState";
import { PINBOARD_TELEMETRY_TYPE, TelemetryContext } from "./types/Telemetry";
import { IMAGING_REQUEST_ITEM_TYPE } from "../../shared/octopusImaging";

interface WithEntity<E> {
entity: E & {
Expand Down Expand Up @@ -295,9 +296,11 @@ export const ItemInputBox = ({
((event) => {
event.stopPropagation();
if (isHardReturn(event)) {
if (
!isAsGridPayloadLoading &&
(message?.trim() || payloadToBeSent)
const hasSomethingToSend =
payloadToBeSent?.type === IMAGING_REQUEST_ITEM_TYPE
? message
: message?.trim() || payloadToBeSent;
if (!isAsGridPayloadLoading && hasSomethingToSend
) {
sendItem();
}
Expand Down
24 changes: 18 additions & 6 deletions client/src/payloadDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { PayloadAndType } from "./types/PayloadAndType";
import { neutral, palette, space } from "@guardian/source-foundations";
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 { FloatingClearButton } from "./floatingClearButton";
import { MamVideoDisplay } from "./mam/mamVideoDisplay";
import { IMAGING_REQUEST_ITEM_TYPE } from "shared/octopusImaging";
import { OctopusImagingOrderDisplay } from "./grid/octopusImagingOrderDisplay";

interface PayloadDisplayProps {
payloadAndType: PayloadAndType;
Expand All @@ -22,7 +24,6 @@ export const PayloadDisplay = ({
tab,
shouldNotBeClickable,
}: PayloadDisplayProps) => {
const { payload } = payloadAndType;
const sendTelemetryEvent = useContext(TelemetryContext);
return (
<div
Expand Down Expand Up @@ -58,26 +59,29 @@ export const PayloadDisplay = ({
`}
draggable={!shouldNotBeClickable}
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={
shouldNotBeClickable
? undefined
: () => {
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 Down Expand Up @@ -106,6 +110,14 @@ export const PayloadDisplay = ({
/>
)}

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

{clearPayloadToBeSent && (
<FloatingClearButton clear={clearPayloadToBeSent} />
)}
Expand Down
2 changes: 1 addition & 1 deletion client/src/pinboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ export const Pinboard = ({
onSuccessfulSend={onSuccessfulSend}
payloadToBeSent={maybeEditingItemId ? null : payloadToBeSent}
setPayloadToBeSent={setPayloadToBeSent}
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 @@ -74,7 +74,7 @@ export const SelectPinboard = ({
activePinboards,
activePinboardIds,
payloadToBeSent,
clearPayloadToBeSent,
setPayloadToBeSent,

isExpanded,

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

<PayloadDisplay
payloadAndType={payloadToBeSent}
clearPayloadToBeSent={clearPayloadToBeSent}
clearPayloadToBeSent={() => setPayloadToBeSent(null)}
/>
</div>
)}
Expand Down
4 changes: 3 additions & 1 deletion client/src/sendMessageArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { useConfirmModal } from "./modal";
import { groupToMentionHandle, userToMentionHandle } from "./mentionsUtil";
import { useTourProgress } from "./tour/tourState";
import { demoPinboardData } from "./tour/tourConstants";
import { IMAGING_REQUEST_ITEM_TYPE } from "../../shared/octopusImaging";

interface SendMessageAreaProps {
payloadToBeSent: PayloadAndType | null;
Expand Down Expand Up @@ -219,7 +220,8 @@ export const SendMessageArea = ({
disabled={
isItemSending ||
isAsGridPayloadLoading ||
!(message?.trim() || payloadToBeSent)
!(message?.trim() || payloadToBeSent) ||
(payloadToBeSent?.type === IMAGING_REQUEST_ITEM_TYPE && !message)
}
>
{isItemSending ? (
Expand Down
28 changes: 25 additions & 3 deletions client/src/types/PayloadAndType.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import * as Sentry from "@sentry/react";
import {
IMAGING_REQUEST_ITEM_TYPE,
ImagingRequestType,
} from "shared/octopusImaging";

export const sources = ["grid", "mam"] as const;
export const sourceTypes = ["crop", "original", "search", "video"] as const;
Expand All @@ -10,10 +14,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}`; // TODO improve this type as it enumerates all the combinations, e.g. mam-original which is not valid
export type PayloadType =
| `${Source}-${SourceType}`
| typeof IMAGING_REQUEST_ITEM_TYPE; // TODO improve this type as it enumerates all the combinations, e.g. mam-original which is not valid
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 All @@ -34,10 +43,15 @@ export interface PayloadWithApiUrl extends PayloadCommon {
apiUrl: string;
}

export interface PayloadWithRequestType extends PayloadWithThumbnail {
requestType: ImagingRequestType;
}

export type Payload =
| PayloadWithThumbnail
| PayloadWithApiUrl
| PayloadWithExternalUrl;
| PayloadWithExternalUrl
| PayloadWithRequestType;
export const isPayload = (maybePayload: unknown): maybePayload is Payload => {
return (
typeof maybePayload === "object" &&
Expand All @@ -62,10 +76,16 @@ export type MamVideoPayload = {
payload: PayloadWithExternalUrl;
};

export type ImagingOrderPayload = {
type: typeof IMAGING_REQUEST_ITEM_TYPE;
payload: PayloadWithRequestType;
};

export type PayloadAndType =
| StaticGridPayload
| DynamicGridPayload
| MamVideoPayload;
| MamVideoPayload
| ImagingOrderPayload;

export const buildPayloadAndType = (
type: string,
Expand All @@ -86,6 +106,8 @@ export const buildPayloadAndType = (
"externalUrl" in payload
) {
return { type, payload };
} else if (type === IMAGING_REQUEST_ITEM_TYPE && "requestType" in payload) {
return { type, payload };
}
};

Expand Down
1 change: 1 addition & 0 deletions client/src/types/Telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export enum PINBOARD_TELEMETRY_TYPE {
FLOATY_EXPANDED = "FLOATY_EXPANDED",
FLOATY_CLOSED = "FLOATY_CLOSED",
ADD_TO_PINBOARD_BUTTON = "ADD_TO_PINBOARD_BUTTON",
IMAGING_REQUEST_VIA_BUTTON = "IMAGING_REQUEST_VIA_BUTTON",
OPEN_FEEDBACK_FORM = "OPEN_FEEDBACK_FORM",
OPEN_FEEDBACK_CHAT = "OPEN_FEEDBACK_CHAT",
EXPAND_FEEDBACK_DETAILS = "OPEN_FEEDBACK_FORM",
Expand Down
9 changes: 9 additions & 0 deletions shared/octopusImaging.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const IMAGING_REQUEST_ITEM_TYPE = "imaging-request";

export const IMAGINE_REQUEST_TYPES = [
"Cut out", // only 'cut out' is required for now
// "Break out",
// "Retouch",
] as const;

export type ImagingRequestType = (typeof IMAGINE_REQUEST_TYPES)[number];

0 comments on commit 0d7dd60

Please sign in to comment.