Created
January 9, 2020 12:51
-
-
Save SvitlanaShepitsena/0a755feaddc71e77ed90789363082308 to your computer and use it in GitHub Desktop.
PostForm created with RenderProps Approach
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component, createRef } from 'react' | |
import styled from 'styled-components' | |
import CKeditor from 'react-ckeditor-component' | |
import { withRouter } from 'next/router' | |
import { SortableContainer, arrayMove } from 'react-sortable-hoc' | |
import { Mutation, Query } from 'react-apollo' | |
import axios from 'axios' | |
import CancelSubmitButtons from '../../common/buttons/CancelSubmitButtons' | |
import RemoveButton from '../../common/buttons/RemoveButton' | |
// todo: remove on prod | |
import { Field, Formik } from 'formik' | |
import Dropzone from 'react-dropzone' | |
import { | |
Grid, | |
Card, | |
Form, | |
Header, | |
Icon, | |
Input, | |
Loader, | |
Message | |
} from 'semantic-ui-react' | |
import parseVideo from '../../filters/parseVideo' | |
import combineVideo from '../../filters/combineVideo' | |
import InputField from './InputField' | |
import VideoContainer from '../../common/media/video/VideoContainer' | |
import StyledPostForm from '../../common/Styled_Components/Styled_PostForm' | |
import { CREATE_POST } from '../../../api/mutations/post/createPost' | |
import TYPE_SECTIONS from '../../../api/queries/post/typeSections' | |
import PROJECT_ADDRESSES from '../../../api/queries/project/projectAddress' | |
import PROJECT_TYPES from '../../../api/queries/post/projectTypes' | |
import * as yup from 'yup' | |
import withUser from '../../../lib/withUser' | |
import DatePicker from 'react-datepicker' | |
import SortableImage from './SortableImage' | |
import uploadImage from '../../../lib/utils/uploadImage' | |
import ImageBackground from '../../common/media/images/ImageBackground' | |
import moment from 'moment' | |
import constants from '../../../api/constants' | |
const SortableList = SortableContainer( | |
({ items, deleteGalImage, changeCaption, loadingImage }) => { | |
return ( | |
<Grid stackable columns={4}> | |
{items.map((value, index) => ( | |
<SortableImage | |
key={`item-${index}`} | |
index={index} | |
loadingImage={loadingImage} | |
imageIndex={index} | |
image={value} | |
delete={deleteGalImage} | |
changeCaption={changeCaption} | |
/> | |
))} | |
</Grid> | |
) | |
} | |
) | |
let newPostSchema = yup.object().shape({ | |
customAuthor: yup.string(), | |
name: yup | |
.string() | |
.required('Title is required') | |
.max(160, 'Title should be less than 160 symbols'), | |
email: yup.string().email('Please provide a valid email'), | |
phone: yup.string(), | |
description: yup | |
.string() | |
.required('Description is required') | |
.max(100, 'Description should be less than 150 symbols'), | |
tags: yup.string() | |
}) | |
class PostForm extends Component { | |
state = { | |
loadingImage: -1, | |
content: 'Post Content', | |
id: '', | |
projectType: '', | |
projectAddress: '', | |
fullVideo: '', | |
videoSource: '', | |
startTime: moment() | |
.startOf('hour') | |
.add(2, 'hours') | |
.format('MM/DD/YYYY hh:mm A'), | |
endTime: moment() | |
.startOf('hour') | |
.add(4, 'hours') | |
.format('MM/DD/YYYY hh:mm A'), | |
video: '', | |
files: [], | |
imageFile: '', | |
imagePrev: '', | |
image: '', | |
contentError: false, | |
loading: false, | |
startTimeError: false, | |
endTimeError: false | |
} | |
deleteGalImage = (index) => { | |
const files = [...this.state.files] | |
files.splice(index, 1) | |
this.setState({ files }) | |
} | |
onSortEnd = ({ oldIndex, newIndex }) => { | |
this.setState(({ files }) => ({ | |
files: arrayMove(files, oldIndex, newIndex) | |
})) | |
} | |
componentDidMount () { | |
if (this.props.post) { | |
let startTime = new Date(this.props.post.startTime) | |
let endTime = new Date(this.props.post.endTime) | |
if (this.props.post && startTime) { | |
this.setState({ | |
...this.props.post, | |
startTime: `${startTime.toLocaleDateString()} ${startTime.toLocaleTimeString()}`, | |
endTime: `${endTime.toLocaleDateString()} ${endTime.toLocaleTimeString()}`, | |
files: this.props.post.galImages | |
}) | |
} | |
} | |
} | |
handleChangeDatePickerStart = (date) => { | |
this.setState({ | |
startTime: date.toLocaleDateString() + ' ' + date.toLocaleTimeString(), | |
startTimeError: false | |
}) | |
} | |
handleChangeDatePickerEnd = (date) => { | |
this.setState({ | |
endTime: date.toLocaleDateString() + ' ' + date.toLocaleTimeString(), | |
endTimeError: false | |
}) | |
} | |
handleChange = (event, data) => { | |
if (!event.target.name) { | |
this.setState({ section: data.value, contentError: false }) | |
} else { | |
this.setState({ [event.target.name]: event.target.value }) | |
let { name, value } = event.target | |
if (name === 'fullVideo') { | |
var videoObject = parseVideo(value) | |
this.setState({ | |
videoSource: videoObject.type, | |
video: videoObject.key | |
}) | |
} | |
} | |
} | |
handleDrop = (files) => { | |
this.setState({ | |
image: files[0].preview, | |
imagePrev: files[0].preview, | |
imageFile: files[0] | |
}) | |
} | |
handleDropGallery = (files) => { | |
let filesWithCaption = files.map((file) => ({ | |
file: file, | |
caption: '', | |
order: -1 | |
})) | |
this.setState((prevState) => ({ | |
files: [...prevState.files, ...filesWithCaption] | |
})) | |
} | |
changeCaption = (index, caption) => { | |
let galImages = [...this.state.files] | |
galImages[index].caption = caption | |
this.setState({ files: galImages }) | |
} | |
onBlur = (evt) => { | |
if (this.state.content.length === 0) { | |
this.setState({ contentError: true }) | |
} | |
} | |
onChange = (evt) => { | |
let newContent = evt.editor.getData() | |
this.setState({ | |
content: newContent | |
}) | |
} | |
render () { | |
let { | |
id, | |
image, | |
projectAddress, | |
projectType, | |
content, | |
video, | |
imagePrev, | |
fullVideo, | |
videoSource, | |
startTime, | |
endTime | |
} = this.state | |
const { postType, post } = this.props | |
let authorNameLabel = | |
this.props.postType === 'Classified' || this.props.postType === 'Event' | |
? 'Contact Name' | |
: 'Custom Author Name' | |
let authorNamePlaceholder = | |
this.props.postType === 'Classified' || this.props.postType === 'Event' | |
? 'Please Enter a Contact Name' | |
: 'Custom Author Name (Optional)' | |
let postTitleLabel = `${this.props.postType} Title` | |
let postTitlePlaceholder = `Give Your ${this.props.postType} a Title` | |
let postDescriptionLabel = `${this.props.postType} Description` | |
let postDescriptionPlaceholder = `Give Your ${ | |
this.props.postType | |
} a Short Description` | |
let postSectionLabel = `${this.props.postType} Section` | |
const descriptionMessage = `Short description will appear on an ${ | |
this.props.postType | |
} thumb and on a web search description of your ${this.props.postType}` | |
const videoMessage = `A video will always appear on an ${ | |
this.props.postType | |
} thumbnail even if you have another media (gallery/images).` | |
const coverImageMessage = `Cover image will appear on an article thumb ONLY if the article does not have photo gallery or video"` | |
return ( | |
<Mutation mutation={CREATE_POST}> | |
{(createPost, { loading, error, data }) => ( | |
<Query | |
query={TYPE_SECTIONS} | |
variables={{ | |
postType: post ? post.postType : postType | |
}} | |
fetchPolicy='cache-and-network' | |
notifyOnNetworkStatusChange | |
> | |
{({ data, loading, error }) => { | |
if (loading || error) { | |
return null | |
} | |
let { typeSections } = data | |
let semanticTypes | |
if (typeSections) { | |
semanticTypes = typeSections.map((typeSection) => { | |
return { | |
key: typeSection.id, | |
text: typeSection.name, | |
value: typeSection.id | |
} | |
}) | |
} | |
return ( | |
<Query | |
query={PROJECT_TYPES} | |
fetchPolicy='cache-and-network' | |
notifyOnNetworkStatusChange | |
> | |
{({ data, loading, error }) => { | |
if (loading || error) { | |
return null | |
} | |
let { projectTypes } = data | |
let projTypeSelect | |
if (projectTypes) { | |
projTypeSelect = projectTypes.map((projType) => { | |
return { | |
key: projType.id, | |
text: projType.name, | |
value: projType.id | |
} | |
}) | |
} | |
return ( | |
<Query | |
query={PROJECT_ADDRESSES} | |
fetchPolicy='cache-and-network' | |
notifyOnNetworkStatusChange | |
> | |
{({ data, loading, error }) => { | |
if (loading || error || !data) { | |
return null | |
} | |
let { projectAddresses } = data | |
let projectAddressesSelect | |
if (projectAddresses && projectAddresses.length) { | |
projectAddressesSelect = projectAddresses.map( | |
(pa) => { | |
return { | |
key: pa.id, | |
text: | |
(pa.house && `${pa.house} `) + | |
(pa.street && `${pa.street} `) + | |
(pa.city && `${pa.city} `) + | |
(pa.zip && `${pa.zip} `), | |
value: pa.id | |
} | |
} | |
) | |
} | |
return ( | |
<> | |
{loading && <Loader />} | |
{error && ( | |
<span> | |
Error.... | |
{error.toString()} | |
</span> | |
)} | |
<Formik | |
initialValues={{ | |
postType: this.props.postType, | |
section: | |
post && post.section | |
? post.section.id | |
: (Boolean( | |
typeSections && typeSections.length | |
) && | |
typeSections[0].id) || | |
'', | |
projectType: post | |
? post.projectType.id | |
: (Boolean( | |
projectTypes && projectTypes.length | |
) && | |
projectTypes[0].key) || | |
'', | |
projectAddress: post | |
? post.projectAddress.id | |
: (Boolean( | |
projectAddresses && | |
projectAddresses.length | |
) && | |
projectAddresses[0].key) || | |
'', | |
name: post | |
? post.name | |
: `Article Title ${Math.random()}`, | |
email: post | |
? post.email | |
: this.props.user.email, | |
phone: post ? post.phone : '', | |
address: post ? post.address : '', | |
tickets: post | |
? post.tickets | |
: `www.tickets.com`, | |
customAuthor: post | |
? post.customAuthor | |
: constants.COMPANY_NAME, | |
description: post | |
? post.description | |
: 'Description', | |
content: post ? post.content : '', | |
tags: post | |
? post.tags.map((t) => t.name).join(' ') | |
: '' | |
}} | |
onSubmit={async ( | |
{ | |
postType, | |
projectAddress, | |
projectType, | |
section, | |
address, | |
tickets, | |
name, | |
email, | |
phone, | |
customAuthor, | |
description, | |
tags | |
}, | |
{ | |
setSubmitting, | |
setFieldValue, | |
setFieldError, | |
setStatus | |
} | |
) => { | |
setSubmitting(true) | |
if (postType === 'Events') { | |
postType = 'Event' | |
} | |
if (section && section.id) { | |
let refCopy = section.id | |
section = section.id | |
setFieldValue({ section: refCopy }) | |
} | |
const formData = new FormData() | |
formData.append('file', this.state.imageFile) | |
formData.append( | |
'upload_preset', | |
process.env.CLOUDINARY_PRESET | |
) // Replace the preset name with your own | |
formData.append( | |
'api_key', | |
process.env.CLOUDINARY_KEY | |
) // Replace API key with your own Cloudinary key | |
formData.append( | |
'timestamp', | |
(Date.now() / 1000) | 0 | |
) | |
let response | |
if (this.state.imageFile) { | |
try { | |
response = await axios.post( | |
`https://api.cloudinary.com/v1_1/${ | |
process.env.CLOUDINARY_NAME | |
}/image/upload`, | |
formData, | |
{ | |
headers: { | |
'X-Requested-With': | |
'XMLHttpRequest' | |
} | |
} | |
) | |
} catch (error) { | |
console.log(error) | |
} | |
} | |
if (this.state.files.length > 0) { | |
for ( | |
let i = 0; | |
i < this.state.files.length; | |
i++ | |
) { | |
this.setState({ loadingImage: i }) | |
const file = this.state.files[i] | |
let fileUrl = await uploadImage(file) | |
const stateFiles = [...this.state.files] | |
stateFiles[i] = { | |
url: fileUrl, | |
caption: file.caption, | |
order: i | |
} | |
this.setState({ files: stateFiles }) | |
} | |
} | |
if ( | |
postType === 'Event' && | |
(this.state.startTime === '' || | |
this.state.endTime === '') | |
) { | |
if (this.state.startTime === '') { | |
this.setState({ startTimeError: true }) | |
} | |
if (this.state.endTime === '') { | |
this.setState({ | |
endTimeError: true | |
}) | |
} | |
setSubmitting(false) | |
} else { | |
if (!projectType) { | |
projectType = projectTypes[0].id | |
} | |
if (!projectAddress) { | |
projectAddress = projectAddresses[0].id | |
} | |
createPost({ | |
variables: { | |
id, | |
postType: post | |
? post.postType | |
: postType, | |
projectType, | |
projectAddress, | |
email, | |
address, | |
startTime, | |
endTime, | |
tickets, | |
phone, | |
name, | |
customAuthor, | |
section, | |
description, | |
content, | |
image: | |
response && | |
response.data && | |
response.data.secure_url | |
? response.data.secure_url | |
: image, | |
video, | |
videoSource, | |
tags, | |
galImages: JSON.stringify( | |
this.state.files | |
) | |
} | |
}) | |
.then((res) => { | |
let url = | |
this.props.postType | |
.toLowerCase() | |
.indexOf('blog') > -1 | |
? this.props.postType.toLowerCase() | |
: this.props.postType.toLowerCase() + | |
's' | |
// console.log('congratulations!!!') | |
this.props.router.push(`/${url}`) | |
}) | |
.catch((err) => { | |
setStatus({ | |
msg: err.message | |
}) | |
setSubmitting(false) | |
}) | |
.finally(() => setSubmitting(false)) | |
} | |
}} | |
validationSchema={newPostSchema} | |
render={({ | |
values, | |
status, | |
handleSubmit, | |
isSubmitting, | |
setFieldValue, | |
handleChange, | |
handleBlur, | |
errors, | |
touched | |
}) => { | |
if (image) { | |
imagePrev = image | |
} | |
if (videoSource && video) { | |
fullVideo = combineVideo(video, videoSource) | |
} | |
return ( | |
<StyledPostForm onSubmit={handleSubmit}> | |
<FixedNav> | |
{this.state.loading || loading ? ( | |
<Loader active inline /> | |
) : ( | |
<CancelSubmitButtons | |
marginbottom='0' | |
onClick={this.props.handleChangeNotEditable()} | |
disabled={isSubmitting} | |
/> | |
)} | |
</FixedNav> | |
<HeaderStyled size='large'> | |
Write a New {this.props.postType} | |
</HeaderStyled> | |
<Grid stackable columns={2}> | |
<Grid.Column> | |
<Form.Field> | |
<label>{authorNameLabel}</label> | |
<Field | |
component={InputField} | |
name='customAuthor' | |
placeholder={ | |
authorNamePlaceholder | |
} | |
/> | |
</Form.Field> | |
</Grid.Column> | |
<Grid.Column> | |
{this.props.postType !== | |
'Project' && ( | |
<Form.Field> | |
<label>{postSectionLabel}</label> | |
<Field | |
component='select' | |
name='section' | |
placeholder='Select a Section' | |
> | |
{semanticTypes.map( | |
({ key, text, value }) => ( | |
<option | |
key={key} | |
value={value} | |
> | |
{text} | |
</option> | |
) | |
)} | |
</Field> | |
</Form.Field> | |
)} | |
</Grid.Column> | |
</Grid> | |
<Grid stackable columns={2}> | |
{this.props.postType === 'Project' && | |
projTypeSelect && ( | |
<Grid.Column> | |
<Field | |
component='select' | |
name='projectType' | |
placeholder='Select a project type' | |
> | |
{projTypeSelect.map( | |
({ key, text, value }) => ( | |
<option | |
key={key} | |
value={value} | |
> | |
{text} | |
</option> | |
) | |
)} | |
</Field> | |
</Grid.Column> | |
)} | |
{this.props.postType === 'Project' && | |
projectAddressesSelect && ( | |
<Grid.Column> | |
<Field | |
component='select' | |
name='projectAddress' | |
placeholder='Select a project address' | |
> | |
{projectAddressesSelect.map( | |
({ key, text, value }) => ( | |
<option | |
key={key} | |
value={value} | |
> | |
{text} | |
</option> | |
) | |
)} | |
</Field> | |
</Grid.Column> | |
)} | |
</Grid> | |
{this.props.postType === 'Event' && ( | |
<Grid stackable columns={2}> | |
<Grid.Column> | |
<Form.Field> | |
<label>Event Address</label> | |
<Field | |
name='address' | |
component={InputField} | |
placeholder='Provide an Event Address' | |
/> | |
</Form.Field> | |
</Grid.Column> | |
<Grid.Column> | |
<Grid stackable columns={2}> | |
<Grid.Column> | |
<Form.Field> | |
<label>Start Time</label> | |
<DatePicker | |
value={this.state.startTime} | |
onChange={ | |
this | |
.handleChangeDatePickerStart | |
} | |
showTimeSelect | |
timeFormat='h:mmaa' | |
timeIntervals={30} | |
dateFormat='MMMM d, yyyy h:mm aa' | |
timeCaption='time' | |
/> | |
</Form.Field> | |
{this.state.startTimeError && ( | |
<Error> | |
Please specify an event | |
start time | |
</Error> | |
)} | |
</Grid.Column> | |
<Grid.Column> | |
<Form.Field> | |
<label>End Time</label> | |
<DatePicker | |
value={this.state.endTime} | |
onChange={ | |
this | |
.handleChangeDatePickerEnd | |
} | |
showTimeSelect | |
timeFormat='h:mmaa' | |
timeIntervals={15} | |
dateFormat='MMMM d, yyyy h:mm aa' | |
timeCaption='time' | |
/> | |
</Form.Field> | |
{this.state.endTimeError && ( | |
<Error> | |
Please specify event end | |
time{' '} | |
</Error> | |
)} | |
</Grid.Column> | |
</Grid> | |
</Grid.Column> | |
</Grid> | |
)} | |
{(this.props.postType === 'Classified' || | |
this.props.postType === 'Event') && ( | |
<Grid stackable columns={2}> | |
<Grid.Column> | |
<Form.Field> | |
<label>Contact email</label> | |
<Field | |
name='email' | |
component={InputField} | |
placeholder='Contact Email (optional)' | |
/> | |
</Form.Field> | |
</Grid.Column> | |
<Grid.Column> | |
<Form.Field> | |
<label>Contact Phone</label> | |
<Field | |
name='phone' | |
component={InputField} | |
placeholder='Contact Phone (optional)' | |
/> | |
</Form.Field> | |
</Grid.Column> | |
</Grid> | |
)} | |
{this.props.postType === 'Event' && ( | |
<Grid stackable columns={1}> | |
<Grid.Column> | |
<Form.Field> | |
<label>Tickets:</label> | |
<Field | |
name='tickets' | |
component={InputField} | |
placeholder='place to buy tickets' | |
/> | |
</Form.Field> | |
</Grid.Column> | |
</Grid> | |
)} | |
<Grid stackable columns={1}> | |
<Grid.Column> | |
<Form.Field> | |
<label>{postTitleLabel}</label> | |
<Field | |
component={InputField} | |
name='name' | |
placeholder={postTitlePlaceholder} | |
/> | |
</Form.Field> | |
</Grid.Column> | |
</Grid> | |
{this.props.postType !== 'Classified' && ( | |
<Grid stackable columns={1}> | |
<Grid.Column> | |
<Form.Field> | |
<label> | |
{postDescriptionLabel} | |
</label> | |
<Field | |
name='description' | |
component={InputField} | |
placeholder={ | |
postDescriptionPlaceholder | |
} | |
/> | |
<StyledMessage | |
visible | |
warning | |
content={descriptionMessage} | |
/> | |
</Form.Field> | |
</Grid.Column> | |
</Grid> | |
)} | |
<Grid stackable columns={2}> | |
<Grid.Column> | |
<Header as='h3'>Cover Image</Header> | |
<Form.Field> | |
<Dropzone | |
className={'dropzoneStyle'} | |
onDrop={this.handleDrop} | |
accept='image/*' | |
> | |
Upload Cover Image | |
</Dropzone> | |
{this.props.postType === 'Blog' && ( | |
<StyledMessage | |
visible | |
warning | |
content={coverImageMessage} | |
/> | |
)} | |
{imagePrev && ( | |
<CoverImageContainer> | |
<ImageBackground | |
imageHeight='220px' | |
image={imagePrev} | |
/> | |
<RemoveButton | |
onClick={() => | |
this.setState({ | |
imagePrev: '', | |
imageFile: '', | |
image: '' | |
}) | |
} | |
/> | |
</CoverImageContainer> | |
)} | |
</Form.Field> | |
</Grid.Column> | |
<Grid.Column> | |
<Header as='h3'>Video</Header> | |
<Form.Field> | |
<Input | |
name='fullVideo' | |
label='https://' | |
placeholder='Video URL' | |
icon={<Icon name='video' />} | |
onChange={this.handleChange} | |
autoComplete='fullVideo' | |
value={fullVideo} | |
/> | |
<StyledMessage | |
visible | |
warning | |
content={videoMessage} | |
/> | |
</Form.Field> | |
{fullVideo ? ( | |
<Card> | |
<VideoContainer | |
video={video} | |
videoSource={videoSource} | |
/> | |
</Card> | |
) : null} | |
</Grid.Column> | |
</Grid> | |
<Grid stackable columns={1}> | |
<Grid.Column> | |
<Header as='h3'> | |
Gallery Images | |
</Header> | |
<hr /> | |
<Form.Field> | |
<Dropzone | |
className={'dropzoneStyle'} | |
onDrop={this.handleDropGallery} | |
accept='image/*' | |
> | |
Upload Gallery Images | |
</Dropzone> | |
<br /> | |
{Boolean( | |
this.state.files.length | |
) && ( | |
<SortableList | |
axis='xy' | |
items={this.state.files} | |
loadingImage={ | |
this.state.loadingImage | |
} | |
onSortEnd={this.onSortEnd} | |
deleteGalImage={ | |
this.deleteGalImage | |
} | |
changeCaption={ | |
this.changeCaption | |
} | |
/> | |
)} | |
</Form.Field> | |
</Grid.Column> | |
</Grid> | |
<Grid stackable columns={1}> | |
<Grid.Column> | |
<Form.Field> | |
{this.state.loading || loading ? ( | |
<Loader active inline /> | |
) : ( | |
<ButtonsFloat> | |
<CancelSubmitButtons | |
marginbottom='0' | |
onClick={this.props.handleChangeNotEditable()} | |
disabled={isSubmitting} | |
/> | |
</ButtonsFloat> | |
)} | |
<Header as='h3'>Content</Header> | |
<hr /> | |
<CKeditor | |
activeClass='p10' | |
id='postEditor' | |
content={this.state.content} | |
events={{ | |
blur: this.onBlur, | |
afterPaste: this.afterPaste, | |
change: this.onChange | |
}} | |
/> | |
</Form.Field> | |
{this.state.contentError && ( | |
<Error> | |
Content cannot be empty | |
</Error> | |
)} | |
</Grid.Column> | |
</Grid> | |
<Grid stackable columns={1}> | |
<Grid.Column> | |
<Form.Field> | |
<label>Tags</label> | |
<Field | |
component={InputField} | |
name='tags' | |
placeholder='Please Provide Some Tags' | |
/> | |
</Form.Field> | |
{status && status.msg && ( | |
<Message | |
negative | |
header='Ooops!' | |
content={status.msg} | |
/> | |
)} | |
</Grid.Column> | |
</Grid> | |
<Grid stackable columns={1}> | |
<Grid.Column> | |
<Form.Field> | |
{this.state.loading || loading ? ( | |
<Loader active inline /> | |
) : ( | |
<CancelSubmitButtons | |
marginbottom='0' | |
onClick={this.props.handleChangeNotEditable()} | |
disabled={isSubmitting} | |
/> | |
)} | |
</Form.Field> | |
</Grid.Column> | |
</Grid> | |
</StyledPostForm> | |
) | |
}} | |
/> | |
</> | |
) | |
}} | |
</Query> | |
) | |
}} | |
</Query> | |
) | |
}} | |
</Query> | |
)} | |
</Mutation> | |
) | |
} | |
} | |
const Error = styled.p` | |
&&& { | |
align-self: center; | |
color: #e74c3c; | |
} | |
` | |
const FixedNav = styled.div` | |
&&& { | |
position: fixed !important; | |
@media only screen and (min-width: 815px) { | |
// background: rgba(0, 0, 0, 0.87); | |
border-bottom-right-radius: 4px; | |
padding: 7px; | |
top: 0px; | |
left: 600px; | |
z-index: 102 !important; | |
max-width: 220px; | |
} | |
@media (max-width: 814px) { | |
top: 10px; | |
right: 10px; | |
} | |
} | |
` | |
const CoverImageContainer = styled(Card)` | |
&&& { | |
position: relative; | |
} | |
` | |
const HeaderStyled = styled(Header)` | |
&&& { | |
margin-top: 0; | |
@media (max-width: 814px) { | |
padding: 28px 14px 14px; | |
} | |
} | |
` | |
const ButtonsFloat = styled.div` | |
&&& { | |
float: right; | |
position: relative; | |
} | |
` | |
const StyledMessage = styled(Message)` | |
&&& { | |
font-size: 12px; | |
} | |
` | |
export default withUser(withRouter(PostForm)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment