Skip to content

Commit

Permalink
WiP - steps upload methods
Browse files Browse the repository at this point in the history
  • Loading branch information
chrismclarke committed May 1, 2019
1 parent 8aaced9 commit 94826bc
Show file tree
Hide file tree
Showing 12 changed files with 219 additions and 98 deletions.
2 changes: 1 addition & 1 deletion src/components/FileInfo/FileInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export class FileInfo extends React.Component<IProps, IState> {
alignItems="center"
>
<Icon size={24} glyph={this.state.glyph} marginRight="4px" />
<Text clip flex={1}>
<Text clipped={true} flex={1}>
{file.name}
</Text>
<Text small>{this.state.size}</Text>
Expand Down
4 changes: 3 additions & 1 deletion src/components/Form/Select.field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ export const SelectField = ({ input, meta, ...rest }: ISelectFieldProps) => (
<FieldContainer style={rest.style}>
<Select
styles={SelectStyles}
onChange={v => input.onChange(getValueFromSelect(v))}
onChange={v => {
input.onChange(getValueFromSelect(v))
}}
value={getValueForSelect(rest.options, input.value)}
{...defaultProps}
{...rest}
Expand Down
2 changes: 1 addition & 1 deletion src/components/ImageInput/ImageInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const imageSizes = {
normal: 1280,
high: 1920,
}
interface IConvertedFileMeta {
export interface IConvertedFileMeta {
startSize: string
endSize: string
compressionPercent: number
Expand Down
45 changes: 27 additions & 18 deletions src/components/Text/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export interface ITextProps {
// keyof colors returns full object prototype, include typeof for just named keys (i.e. color list)
color?: keyof typeof colors
// clip forces text to fill max 1 line and add '...' for overflow
clip?: boolean
clipped?: boolean
}

export const caps = props =>
Expand All @@ -27,29 +27,29 @@ export const caps = props =>
}
: null

export const inline = props =>
export const inline = (props: ITextProps) =>
props.inline ? { display: 'inline-block' } : null

export const regular = props =>
props.regular ? { fontWeight: props.theme.regular } : null
export const regular = (props: ITextProps) =>
props.regular ? { fontWeight: theme.regular } : null

export const bold = props =>
props.bold ? { fontWeight: props.theme.bold } : null
export const bold = (props: ITextProps) =>
props.bold ? { fontWeight: theme.bold } : null

export const large = props =>
props.large ? { fontSize: props.theme.fontSizes[3] } : null
export const large = (props: ITextProps) =>
props.large ? { fontSize: theme.fontSizes[3] } : null

export const medium = props =>
props.medium ? { fontSize: props.theme.fontSizes[2] } : null
export const medium = (props: ITextProps) =>
props.medium ? { fontSize: theme.fontSizes[2] } : null

export const small = props =>
props.small ? { fontSize: props.theme.fontSizes[1] } : null
export const small = (props: ITextProps) =>
props.small ? { fontSize: theme.fontSizes[1] } : null

export const superSmall = props =>
props.small ? { fontSize: props.theme.fontSizes[0] } : null
export const superSmall = (props: ITextProps) =>
props.small ? { fontSize: theme.fontSizes[0] } : null

export const clip = props =>
props.clip
export const clipped = (props: ITextProps) =>
props.clipped
? { whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }
: null

Expand All @@ -62,13 +62,14 @@ export const BaseText = styled(RebassText)`
${medium}
${small}
${superSmall}
${clip}
${clipped}
`

type TextProps = ITextProps & RebassTextProps

// TODO - incorporate custom css into rebass props to allow things like below to be passed
export const Text = (props: TextProps) => (
<BaseText color={colors[props.color ? props.color : 'black']} {...props}>
<BaseText color={_getTextColor(props)} {...props}>
{props.children}
</BaseText>
)
Expand All @@ -78,4 +79,12 @@ Text.defaultProps = {
className: 'text',
}

function _getTextColor(props: TextProps) {
if (props.color) {
return props.color
} else {
return 'black'
}
}

export default Text
25 changes: 16 additions & 9 deletions src/mocks/tutorials.mock.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { IHowto } from '../models/howto.models'
import { IFirebaseUploadInfo } from 'src/components/FirebaseFileUploader/FirebaseFileUploader'
import { toTimestamp } from 'src/utils/helpers'

const exampleUploadImage: IFirebaseUploadInfo = {
downloadUrl: 'http://placekitten.com/g/400/250',
Expand All @@ -15,7 +16,6 @@ export const TUTORIALS_MOCK: IHowto[] = [
cover_image: exampleUploadImage,
tutorial_title: 'Tutorial 1',
workspace_name: 'Eindhoven Mate',
id: 'fakeid1',
slug: 'tutorial-1',
tutorial_description: 'this is a great description 1',
tutorial_cost: 20,
Expand All @@ -36,14 +36,16 @@ export const TUTORIALS_MOCK: IHowto[] = [
tags: {},
tutorial_extern_file_url: '',
tutorial_files: [],
_created: new Date(),
_modified: new Date(),
_id: 'howTo1',
_deleted: false,
_createdBy: '123',
_created: toTimestamp('Friday, January 2, 2015 12:59 AM'),
_modified: toTimestamp('Friday, January 2, 2015 12:59 AM'),
},
{
cover_image: exampleUploadImage,
tutorial_title: 'Tutorial 2',
workspace_name: 'Eindhoven Mate',
id: 'fakeid2',
slug: 'tutorial-2',
tutorial_description: 'this is a great description 2',
tutorial_cost: 20,
Expand All @@ -64,14 +66,16 @@ export const TUTORIALS_MOCK: IHowto[] = [
tags: {},
tutorial_extern_file_url: '',
tutorial_files: [],
_created: new Date(),
_modified: new Date(),
_id: 'howTo2',
_deleted: false,
_createdBy: '123',
_created: toTimestamp('Friday, January 2, 2015 12:59 AM'),
_modified: toTimestamp('Friday, January 2, 2015 12:59 AM'),
},
{
cover_image: exampleUploadImage,
tutorial_title: 'Tutorial 3',
workspace_name: 'Eindhoven Mate',
id: 'fakeid3',
slug: 'tutorial-3',
tutorial_description: 'this is a great description 3',
tutorial_cost: 20,
Expand All @@ -92,7 +96,10 @@ export const TUTORIALS_MOCK: IHowto[] = [
tags: {},
tutorial_extern_file_url: '',
tutorial_files: [],
_created: new Date(),
_modified: new Date(),
_id: 'howTo3',
_deleted: false,
_createdBy: '123',
_created: toTimestamp('Friday, January 2, 2015 12:59 AM'),
_modified: toTimestamp('Friday, January 2, 2015 12:59 AM'),
},
]
23 changes: 11 additions & 12 deletions src/models/howto.models.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,38 @@
import { ISelectedTags } from './tags.model'
import { IFirebaseUploadInfo } from 'src/components/FirebaseFileUploader/FirebaseFileUploader'
import { IDbDoc } from './common.models'
import { IConvertedFileMeta } from 'src/components/ImageInput/ImageInput'
import { IUploadedFileMeta } from 'src/stores/storage'

// By default all tutorial form input fields come as strings
// The IHowto interface imposes the correct formats on fields
// The IHowto interface can imposes the correct formats on fields
// adds additional populated meta fields, and forces cover image
export interface IHowto extends IHowtoFormInput {
tutorial_cost: number
cover_image: IFirebaseUploadInfo
_created: Date
_modified: Date
export interface IHowto extends IHowtoFormInput, IDbDoc {
cover_image: IUploadedFileMeta
}

export interface IHowtoStep {
// *** NOTE legacy format only tracked urls - this will be removed once data upgraded
// *** NOTE 2 - adding an '_animationKey' field to track when specific array element removed for
images: IFirebaseUploadInfo[]
images: IUploadedFileMeta[] | IConvertedFileMeta[]
title: string
text: string
_animationKey?: string
}

export interface IHowtoFormInput {
workspace_name: string
cover_image: IFirebaseUploadInfo | null
// *** NOTE legacy format only tracked urls - this will be removed once data upgraded
// NOTE cover image input starts as convertedFileMeta but is transformed on upload
cover_image: IUploadedFileMeta | IConvertedFileMeta[]
// NOTE legacy format only tracked urls - this will be removed once data upgraded
cover_image_url?: string
tutorial_title: string
tutorial_description: string
difficulty_level: 'Easy' | 'Medium' | 'Hard' | 'Very Hard'
tutorial_time: string
tutorial_cost: any
tutorial_extern_file_url: string
tutorial_files: IFirebaseUploadInfo[]
tutorial_files: IUploadedFileMeta[]
steps: IHowtoStep[]
id: string
slug: string
tags: ISelectedTags
}
71 changes: 25 additions & 46 deletions src/pages/Howto/Content/CreateHowto/CreateHowto.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import arrayMutators from 'final-form-arrays'
import { IHowto, IHowtoFormInput } from 'src/models/howto.models'
import { afs } from 'src/utils/firebase'
import TEMPLATE from './TutorialTemplate'
import { IFirebaseUploadInfo } from 'src/components/FirebaseFileUploader/FirebaseFileUploader'
import { stripSpecialCharacters } from 'src/utils/helpers'
import { UploadedFile } from 'src/pages/common/UploadedFile/UploadedFile'
import { InputField, TextAreaField } from 'src/components/Form/Fields'
Expand All @@ -22,6 +21,8 @@ import { TagsSelectField } from 'src/components/Form/TagsSelect.field'
import { ImageInputField } from 'src/components/Form/ImageInput.field'
import { FileInputField } from 'src/components/Form/FileInput.field'
import posed, { PoseGroup } from 'react-pose'
import { Storage, IUploadedFileMeta } from 'src/stores/storage'
import { IConvertedFileMeta } from 'src/components/ImageInput/ImageInput'

export interface IState {
formValues: IHowtoFormInput
Expand All @@ -35,6 +36,8 @@ const AnimationContainer = posed.div({
enter: { x: 0, opacity: 1, delay: 300 },
exit: { x: 200, opacity: 0, delay: 200 },
})

// validation - return undefined if no error (i.e. valid)
const required = (value: any) => (value ? undefined : 'Required')

export class CreateHowto extends React.PureComponent<
Expand All @@ -49,43 +52,17 @@ export class CreateHowto extends React.PureComponent<
const databaseRef = afs.collection('documentation').doc()
const docID = databaseRef.id
this.state = {
formValues: { ...TEMPLATE.INITIAL_VALUES, id: docID } as IHowtoFormInput,
formValues: { ...TEMPLATE.TESTING_VALUES, id: docID } as IHowtoFormInput,
formSaved: false,
_docID: docID,
_uploadPath: `uploads/documentation/${docID}`,
_toDocsList: false,
}
}

public initialiseValues() {}

public onSubmit = async (formValues: IHowtoFormInput) => {
const inputValues = formValues as IHowtoFormInput
if (!inputValues.cover_image) {
alert('Please provide a cover image before saving your tutorial')
} else {
const timestamp = new Date()
const slug = stripSpecialCharacters(formValues.tutorial_title)
// convert data to correct types and populate metadata
const values: IHowto = {
...formValues,
slug,
tutorial_cost: Number(formValues.tutorial_cost),
cover_image: formValues.cover_image as IFirebaseUploadInfo,
_created: timestamp,
_modified: timestamp,
}
try {
await afs
.collection('documentation')
.doc(formValues.id)
.set(values)
this.setState({ formSaved: true })
this.props.history.push('/how-to/' + slug)
} catch (error) {
console.log('error while saving the tutorial')
}
}
console.log('submitting')
// this.injected.store
}

public validateTitle = async (value: any, meta?: FieldState) => {
Expand All @@ -110,7 +87,6 @@ export class CreateHowto extends React.PureComponent<

public render() {
const { formValues } = this.state
console.log('formvalues', formValues)
return (
<>
<Form
Expand All @@ -120,18 +96,8 @@ export class CreateHowto extends React.PureComponent<
validateOnBlur
mutators={{
...arrayMutators,
clearCoverImage: (args, state, utils) => {
utils.changeValue(state, 'cover_image', () => null)
},
}}
render={({
handleSubmit,
mutators,
submitting,
values,
form,
invalid,
}) => {
render={({ handleSubmit, submitting, values, invalid, errors }) => {
const v = values as IHowto
const disabled = invalid || submitting
return (
Expand All @@ -157,18 +123,21 @@ export class CreateHowto extends React.PureComponent<
<FlexContainer p={0}>
<Field
name="tutorial_time"
validate={required}
validateFields={[]}
// TODO - fix validation (#462)
// validate={required}
// validateFields={[]}
options={TEMPLATE.TIME_OPTIONS}
component={SelectField}
placeholder="How much time? *"
style={{ marginRight: '4px' }}
/>
<Field
name="difficulty_level"
// TODO - fix validation (#462)
// validate={required}
// validateFields={[]}
component={SelectField}
options={TEMPLATE.DIFFICULTY_OPTIONS}
validateFields={[]}
placeholder="How hard is it? *"
style={{ marginLeft: '4px' }}
/>
Expand All @@ -186,6 +155,9 @@ export class CreateHowto extends React.PureComponent<
<BoxContainer p={0} width={[1, null, '380px']}>
<Field
name="cover_image"
// TODO - fix validation (#462)
// validate={required}
// validateFields={[]}
validateFields={[]}
component={ImageInputField}
text="Cover Image"
Expand All @@ -209,7 +181,9 @@ export class CreateHowto extends React.PureComponent<
step={name}
index={index}
onDelete={(fieldIndex: number) => {
console.log('removing field at index', index)
fields.remove(fieldIndex)
console.log('values', values, errors)
}}
values={values}
_uploadPath={this.state._uploadPath}
Expand All @@ -226,7 +200,6 @@ export class CreateHowto extends React.PureComponent<
variant="dark"
bg="yellow"
onClick={() => {
console.log('adding step', values)
fields.push({
title: '',
text: '',
Expand All @@ -253,6 +226,12 @@ export class CreateHowto extends React.PureComponent<
>
Publish
</Button>
<Button onClick={() => console.log(values)}>
Dev: Log values
</Button>
<Button onClick={() => console.log(errors)}>
Dev: Log validation state
</Button>
</form>
)
}}
Expand Down
Loading

0 comments on commit 94826bc

Please sign in to comment.