diff options
Diffstat (limited to 'packages/website/ts/components/modals')
-rw-r--r-- | packages/website/ts/components/modals/input.tsx | 92 | ||||
-rw-r--r-- | packages/website/ts/components/modals/modal_contact.tsx | 390 |
2 files changed, 0 insertions, 482 deletions
diff --git a/packages/website/ts/components/modals/input.tsx b/packages/website/ts/components/modals/input.tsx deleted file mode 100644 index c72e53aa0..000000000 --- a/packages/website/ts/components/modals/input.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import * as React from 'react'; -import styled from 'styled-components'; - -export enum InputWidth { - Half, - Full, -} - -interface InputProps { - name: string; - width?: InputWidth; - label: string; - type?: string; - errors?: ErrorProps; - isErrors?: boolean; - required?: boolean; -} - -interface ErrorProps { - [key: string]: string; -} - -export const Input = React.forwardRef((props: InputProps, ref?: React.Ref<HTMLInputElement>) => { - const { name, label, type, errors } = props; - const id = `input-${name}`; - const componentType = type === 'textarea' ? 'textarea' : 'input'; - const isErrors = errors.hasOwnProperty(name) && errors[name] !== null; - const errorMessage = isErrors ? errors[name] : null; - - return ( - <InputWrapper {...props}> - <Label htmlFor={id}>{label}</Label> - <StyledInput as={componentType} ref={ref} id={id} isErrors={isErrors} {...props} /> - {isErrors && <Error>{errorMessage}</Error>} - </InputWrapper> - ); -}); - -Input.defaultProps = { - width: InputWidth.Full, - errors: {}, -}; - -const StyledInput = styled.input` - appearance: none; - background-color: #fff; - border: 1px solid #d5d5d5; - color: #000; - font-size: 1.294117647rem; - padding: 16px 15px 14px; - outline: none; - width: 100%; - min-height: ${props => props.type === 'textarea' && `120px`}; - - background-color: ${(props: InputProps) => props.isErrors && `#FDEDED`}; - border-color: ${(props: InputProps) => props.isErrors && `#FD0000`}; - - &::placeholder { - color: #c3c3c3; - } -`; - -const InputWrapper = styled.div<InputProps>` - position: relative; - flex-grow: ${props => props.width === InputWidth.Full && 1}; - width: ${props => props.width === InputWidth.Half && `calc(50% - 15px)`}; - - @media (max-width: 768px) { - width: 100%; - margin-bottom: 30px; - } -`; - -const Label = styled.label` - color: #000; - font-size: 1.111111111rem; - line-height: 1.4em; - margin-bottom: 10px; - display: inline-block; -`; - -const Error = styled.span` - color: #fd0000; - font-size: 0.833333333rem; - line-height: 1em; - display: inline-block; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - transform: translateY(24px); -`; diff --git a/packages/website/ts/components/modals/modal_contact.tsx b/packages/website/ts/components/modals/modal_contact.tsx deleted file mode 100644 index 62c1062a3..000000000 --- a/packages/website/ts/components/modals/modal_contact.tsx +++ /dev/null @@ -1,390 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; -import styled from 'styled-components'; - -import { colors } from 'ts/style/colors'; - -import { DialogContent, DialogOverlay } from '@reach/dialog'; -import '@reach/dialog/styles.css'; - -import { Button } from 'ts/components/button'; -import { Icon } from 'ts/components/icon'; -import { Input, InputWidth } from 'ts/components/modals/input'; -import { Heading, Paragraph } from 'ts/components/text'; -import { GlobalStyle } from 'ts/constants/globalStyle'; -import { utils } from 'ts/utils/utils'; - -export enum ModalContactType { - General = 'GENERAL', - MarketMaker = 'MARKET_MAKER', -} - -interface Props { - theme?: GlobalStyle; - isOpen?: boolean; - onDismiss?: () => void; - modalContactType: ModalContactType; -} - -interface FormProps { - isSuccessful?: boolean; - isSubmitting?: boolean; -} - -interface ErrorResponseProps { - param: string; - location: string; - msg: string; -} - -interface ErrorResponse { - errors: ErrorResponseProps[]; -} - -interface ErrorProps { - [key: string]: string; -} - -export class ModalContact extends React.Component<Props> { - public static defaultProps = { - modalContactType: ModalContactType.General, - }; - public state = { - isSubmitting: false, - isSuccessful: false, - errors: {}, - }; - // shared fields - public nameRef: React.RefObject<HTMLInputElement> = React.createRef(); - public emailRef: React.RefObject<HTMLInputElement> = React.createRef(); - public companyProjectRef: React.RefObject<HTMLInputElement> = React.createRef(); - public commentsRef: React.RefObject<HTMLInputElement> = React.createRef(); - // general lead fields - public linkRef: React.RefObject<HTMLInputElement> = React.createRef(); - // market maker lead fields - public countryRef: React.RefObject<HTMLInputElement> = React.createRef(); - public fundSizeRef: React.RefObject<HTMLInputElement> = React.createRef(); - public constructor(props: Props) { - super(props); - } - public render(): React.ReactNode { - const { isOpen, onDismiss } = this.props; - const { isSuccessful, errors } = this.state; - return ( - <> - <DialogOverlay - style={{ background: 'rgba(0, 0, 0, 0.75)', zIndex: 30 }} - isOpen={isOpen} - onDismiss={onDismiss} - > - <StyledDialogContent> - <Form onSubmit={this._onSubmitAsync.bind(this)} isSuccessful={isSuccessful}> - <Heading color={colors.textDarkPrimary} size={34} asElement="h2"> - Contact the 0x Core Team - </Heading> - {this._renderFormContent(errors)} - <ButtonRow> - <Button - color="#5C5C5C" - isNoBorder={true} - isTransparent={true} - type="button" - onClick={this.props.onDismiss} - > - Back - </Button> - <Button>Submit</Button> - </ButtonRow> - </Form> - <Confirmation isSuccessful={isSuccessful}> - <Icon name="rocketship" size="large" margin={[0, 0, 'default', 0]} /> - <Heading color={colors.textDarkPrimary} size={34} asElement="h2"> - Thanks for contacting us. - </Heading> - <Paragraph isMuted={true} color={colors.textDarkPrimary}> - We'll get back to you soon. If you need quick support in the meantime, reach out to the - 0x team on Discord. - </Paragraph> - <Button onClick={this.props.onDismiss}>Done</Button> - </Confirmation> - </StyledDialogContent> - </DialogOverlay> - </> - ); - } - public _renderFormContent(errors: ErrorProps): React.ReactNode { - switch (this.props.modalContactType) { - case ModalContactType.MarketMaker: - return this._renderMarketMakerFormContent(errors); - case ModalContactType.General: - default: - return this._renderGeneralFormContent(errors); - } - } - private _renderMarketMakerFormContent(errors: ErrorProps): React.ReactNode { - return ( - <> - <Paragraph isMuted={true} color={colors.textDarkPrimary}> - If you’re considering market making on 0x, we’re happy to answer your questions. Fill out the form - so we can connect you with the right person to help you get started. - </Paragraph> - <InputRow> - <Input - name="name" - label="Your name" - type="text" - width={InputWidth.Half} - ref={this.nameRef} - required={true} - errors={errors} - /> - <Input - name="email" - label="Your email" - type="email" - ref={this.emailRef} - required={true} - errors={errors} - width={InputWidth.Half} - /> - </InputRow> - <InputRow> - <Input - name="country" - label="Country of Location" - type="text" - ref={this.countryRef} - required={true} - errors={errors} - /> - </InputRow> - <InputRow> - <Input - name="fundSize" - label="Fund Size" - type="text" - ref={this.fundSizeRef} - required={true} - errors={errors} - /> - </InputRow> - <InputRow> - <Input - name="companyOrProject" - label="Name of your project / company" - type="text" - ref={this.companyProjectRef} - required={false} - errors={errors} - /> - </InputRow> - <InputRow> - <Input - name="comments" - label="What is prompting you to reach out?" - type="textarea" - ref={this.commentsRef} - required={false} - errors={errors} - /> - </InputRow> - </> - ); - } - private _renderGeneralFormContent(errors: ErrorProps): React.ReactNode { - return ( - <> - <Paragraph isMuted={true} color={colors.textDarkPrimary}> - If you're considering building on 0x, we're happy to answer your questions. Fill out the form so we - can connect you with the right person to help you get started. - </Paragraph> - <InputRow> - <Input - name="name" - label="Your name" - type="text" - width={InputWidth.Half} - ref={this.nameRef} - required={true} - errors={errors} - /> - <Input - name="email" - label="Your email" - type="email" - ref={this.emailRef} - required={true} - errors={errors} - width={InputWidth.Half} - /> - </InputRow> - <InputRow> - <Input - name="companyOrProject" - label="Name of your project / company" - type="text" - ref={this.companyProjectRef} - required={true} - errors={errors} - /> - </InputRow> - <InputRow> - <Input - name="link" - label="Do you have any documentation or a website?" - type="text" - ref={this.linkRef} - errors={errors} - /> - </InputRow> - <InputRow> - <Input - name="comments" - label="Anything else?" - type="textarea" - ref={this.commentsRef} - errors={errors} - /> - </InputRow> - </> - ); - } - private async _onSubmitAsync(e: Event): Promise<void> { - e.preventDefault(); - - let jsonBody; - if (this.props.modalContactType === ModalContactType.MarketMaker) { - jsonBody = { - name: this.nameRef.current.value, - email: this.emailRef.current.value, - country: this.countryRef.current.value, - fundSize: this.fundSizeRef.current.value, - projectOrCompany: this.companyProjectRef.current.value, - comments: this.commentsRef.current.value, - }; - } else { - jsonBody = { - name: this.nameRef.current.value, - email: this.emailRef.current.value, - projectOrCompany: this.companyProjectRef.current.value, - link: this.linkRef.current.value, - comments: this.commentsRef.current.value, - }; - } - - this.setState({ ...this.state, errors: [], isSubmitting: true }); - - const endpoint = - this.props.modalContactType === ModalContactType.MarketMaker ? '/market_maker_leads' : '/leads'; - - try { - // Disabling no-unbound method b/c no reason for _.isEmpty to be bound - // tslint:disable:no-unbound-method - const response = await fetch(`${utils.getBackendBaseUrl()}${endpoint}`, { - method: 'post', - mode: 'cors', - credentials: 'same-origin', - headers: { - 'content-type': 'application/json; charset=utf-8', - }, - body: JSON.stringify(_.omitBy(jsonBody, _.isEmpty)), - }); - - if (!response.ok) { - const errorResponse: ErrorResponse = await response.json(); - const errors = this._parseErrors(errorResponse.errors); - this.setState({ ...this.state, isSubmitting: false, errors }); - - throw new Error('Request failed'); - } - - this.setState({ ...this.state, isSuccessful: true }); - } catch (e) { - // Empty block - } - } - private _parseErrors(errors: ErrorResponseProps[]): ErrorProps { - const initialValue: {} = {}; - return _.reduce( - errors, - (hash: ErrorProps, error: ErrorResponseProps) => { - const { param, msg } = error; - const key = param; - hash[key] = msg; - - return hash; - }, - initialValue, - ); - } -} - -// Handle errors: {"errors":[{"location":"body","param":"name","msg":"Invalid value"},{"location":"body","param":"email","msg":"Invalid value"}]} - -const InputRow = styled.div` - width: 100%; - flex: 0 0 auto; - - @media (min-width: 768px) { - display: flex; - justify-content: space-between; - margin-bottom: 30px; - } -`; - -const ButtonRow = styled(InputRow)` - @media (max-width: 768px) { - display: flex; - flex-direction: column; - - button:nth-child(1) { - order: 2; - } - - button:nth-child(2) { - order: 1; - margin-bottom: 10px; - } - } -`; - -const StyledDialogContent = styled(DialogContent)` - position: relative; - max-width: 800px; - background-color: #f6f6f6 !important; - padding: 60px 60px !important; - - @media (max-width: 768px) { - width: calc(100vw - 40px) !important; - margin: 40px auto !important; - padding: 30px 30px !important; - } -`; - -const Form = styled.form<FormProps>` - position: relative; - transition: opacity 0.3s ease-in-out, visibility 0.3s ease-in-out; - - opacity: ${props => props.isSuccessful && `0`}; - visibility: ${props => props.isSuccessful && `hidden`}; -`; - -const Confirmation = styled.div<FormProps>` - position: absolute; - top: 50%; - text-align: center; - width: 100%; - left: 0; - transition: opacity 0.3s ease-in-out, visibility 0.3s ease-in-out; - transition-delay: 0.4s; - padding: 60px 60px; - transform: translateY(-50%); - opacity: ${props => (props.isSuccessful ? `1` : `0`)}; - visibility: ${props => (props.isSuccessful ? 'visible' : `hidden`)}; - - p { - max-width: 492px; - margin-left: auto; - margin-right: auto; - } -`; |