client/components/helpCentre/contactUs/UploadFileInput.tsx (160 lines of code) (raw):

import type { SerializedStyles } from '@emotion/react'; import { css } from '@emotion/react'; import { focusHalo, height, palette, space, textSansBold17, transitions, } from '@guardian/source/foundations'; import { Button } from '@guardian/source/react-components'; import Color from 'color'; import { useEffect, useState } from 'react'; import type * as React from 'react'; import { ErrorIcon } from '../../mma/shared/assets/ErrorIcon'; interface UploadFileUploadProps { title: string; allowedFileFormats: string[]; changeSetState?: (value: File | undefined) => void; description?: string; optional?: true; inErrorState?: boolean; errorMessage?: string; additionalCss?: SerializedStyles; } export const UploadFileInput = (props: UploadFileUploadProps) => { const [selectedFile, setSelectedFile] = useState<File | undefined>(); useEffect(() => { props.changeSetState?.(selectedFile); }, [selectedFile, props]); return ( <label css={css` display: block; color: ${palette.neutral['7']}; ${textSansBold17}; ${props.additionalCss} `} > {props.title} {props.optional && ( <span css={css` font-style: italic; font-weight: normal; color: ${palette.neutral['46']}; `} > {' '} optional </span> )} {props.description && ( <span css={css` display: block; font-weight: normal; color: ${palette.neutral['46']}; `} > {props.description} </span> )} {props.inErrorState && ( <span css={css` display: block; font-weight: normal; color: ${palette.error[400]}; `} > <ErrorIcon additionalCss={css` margin-right: 4px; `} /> {props.errorMessage} </span> )} <input type="file" name="imageAttachment" accept={props.allowedFileFormats.join()} multiple={false} css={css` display: none; `} onChange={(e: React.ChangeEvent<HTMLInputElement>) => { const file = e.target.files?.[0]; if (file) { setSelectedFile(file); } }} /> <div css={css` display: block; margin-top: ${space[2]}px; `} > <span css={css` height: ${height.ctaMedium}px; min-height: ${height.ctaMedium}px; padding: 0 ${space[5]}px; border-radius: ${height.ctaMedium}px; display: inline-flex; justify-content: space-between; align-items: center; box-sizing: border-box; border: none; background-color: ${palette.brand[800]}; color: ${palette.brand[400]}; cursor: pointer; transition: ${transitions.medium}; text-decoration: none; white-space: nowrap; &:focus { ${focusHalo}; } &:hover { background-color: ${Color(palette.brand[800], 'hex') .darken(0.1) .string()}; } `} > Choose file </span> {selectedFile && ( <Button priority="subdued" cssOverrides={css` margin-left: ${space[3]}px; text-decoration: underline; `} onClick={(event) => { event.preventDefault(); setSelectedFile(undefined); }} > Cancel </Button> )} <span css={css` display: inline-flex; margin-left: ${space[3]}px; font-weight: normal; color: ${props.inErrorState ? palette.error[400] : palette.neutral['46']}; `} > {selectedFile?.name} </span> </div> </label> ); };