Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/react-scripts/scripts/utils/frontierInit.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@ function installFrontierDependencies(appPath, appName, ownPath) {
'@fs/zion-subnav',
'@fs/zion-user',
'@fs/zion-ui',
'formik',
'i18next@15',
'react-i18next@10',
'prop-types@15',
'yup',
]
)
devDepsToInstall.push(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import LearnReactCard from './LearnReactCard'
import NotSignedInCard from './NotSignedInCard'
import ArtifactsCard from './ArtifactsCard'
import UserCard from './UserCard'
import FormCard from './FormCard/FormCard'

// Hook to generate a random color
const useRandomColor = () => {
Expand Down Expand Up @@ -92,7 +93,7 @@ const ExamplePage = () => {
</Cell>

<Cell sm="6" lg="8">
<div>Form demo coming soon</div>
<FormCard />
</Cell>
</Grid>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import React from 'react'
import { Form, Field, ErrorMessage } from 'formik'
import { Grid, Cell } from '@fs/zion-ui/grid'
import { TextField, Checkbox, FormControlLabel } from '@fs/zion-ui'

export default function Edit({ values, errors }) {
return (
<Form>
<Grid>
<Cell md="6" lg="4">
<Field name="username">
{({ field }) => (
<>
<TextField
{...field}
error={errors.username}
id="username"
label="Username (required)"
/>
<ErrorMessage name="username" render={msg => <p>{msg}</p>} />
</>
)}
</Field>
</Cell>
<Cell md="6" lg="4">
<Field name="password">
{({ field }) => (
<>
<TextField
{...field}
type="password"
error={errors.password}
id="password"
label="Enter a dummy password (required)"
/>
<ErrorMessage name="password" render={msg => <p>{msg}</p>} />
</>
)}
</Field>
</Cell>
<Cell>
<Field name="food">
{({ field }) => (
<>
<TextField
{...field}
error={errors.food}
id="food"
label="What&#39;s your favorite food"
/>
<ErrorMessage name="food" render={msg => <p>{msg}</p>} />
</>
)}
</Field>
</Cell>
<Cell md="6" lg="4">
<Field name="age">
{({ field }) => (
<>
<TextField {...field} type="number" error={errors.age} id="age" label="Age" />
<ErrorMessage name="age" render={msg => <p>{msg}</p>} />
</>
)}
</Field>
</Cell>
<Cell md="6" lg="4">
<Field name="email">
{({ field }) => (
<>
<TextField {...field} error={errors.email} id="email" label="An Email" />
<ErrorMessage name="email" render={msg => <p>{msg}</p>} />
</>
)}
</Field>
</Cell>
<Cell>
<div>
<Field name="debug" type="checkbox">
{({ field }) => (
<>
<FormControlLabel control={<Checkbox {...field} />} label="Debug Formik" />
</>
)}
</Field>
</div>
</Cell>
</Grid>
{values.debug && <pre>{JSON.stringify({ errors, values }, null, 2)}</pre>}
</Form>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import React, { useState, lazy } from 'react'
import { Button, Card, CardActions, CardContent } from '@fs/zion-ui'
import { Formik } from 'formik'
import * as Yup from 'yup'
import { useCache } from '@fs/zion-cache'
import ListData from './ListData'

const EditData = lazy(() => import('./EditData'))

const cache = { dbName: 'formik', storeName: 'example' }
const key = 'example'
const initialValue = {
username: '',
password: '',
food: '',
email: '',
age: undefined,
debug: false,
}
const FormCard = () => {
const [cachedData, setCachedData] = useCache({
cache,
key,
initialValue,
})
const [isEditing, setIsEditing] = useState(false)
const validationSchema = Yup.object().shape({
username: Yup.string()
.min(4, 'Must be at least 4 characters long.')
.max(15, 'Must be less than 15 characters')
.required('Username is required'),
password: Yup.string()
.min(8, 'Must be at least 8 characters')
.max(50, 'Too Long!')
.required('Password is required'),
email: Yup.string().email('Please enter a valid email'),
age: Yup.number()
.min(8)
.max(65),
food: Yup.string().max(50),
})
return (
<Card>
{cachedData && (
<Formik
validationSchema={validationSchema}
initialValues={cachedData}
onSubmit={(values, actions) => {
setCachedData(values)
actions.setSubmitting(false)
setIsEditing(false)
}}
>
{({ values, errors, handleSubmit, isValid, isDirty, resetForm }) => (
<>
<CardContent>
<h2>Forms in React</h2>
<p>
We recommend <a href="https://jaredpalmer.com/formik/">Formik</a>. It&#39;s really
helpful to watch the{' '}
<a href="https://jaredpalmer.com/formik/docs/overview#motivation">
author&#39;s video
</a>{' '}
to understand the why.
</p>
<h3>Example Form</h3>

{isEditing ? (
<EditData errors={errors} values={values} />
) : (
<ListData data={cachedData} />
)}
</CardContent>
<CardActions>
{isEditing ? (
<>
<Button
onClick={() => {
setIsEditing(editing => !editing)
resetForm(cachedData)
}}
variant="outlined"
size="small"
color="secondary"
>
Cancel
</Button>
<Button
onClick={handleSubmit}
disabled={!isDirty && !isValid}
size="small"
color="primary"
>
Save to Local Cache
</Button>
</>
) : (
<>
<Button
disabled={cachedData === undefined}
onClick={() => {
setCachedData(initialValue)
resetForm(initialValue)
}}
variant="outlined"
size="small"
color="secondary"
>
Reset
</Button>
<Button
type="button"
disabled={cachedData === undefined}
onClick={e => {
e.preventDefault()
setIsEditing(editing => !editing)
}}
size="small"
color="primary"
>
Edit
</Button>
</>
)}
</CardActions>
</>
)}
</Formik>
)}
</Card>
)
}

export default FormCard
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react'
import { List, ListItem, ListItemText } from '@fs/zion-ui/list'

export default function ListData({ data }) {
return (
<List>
<ListItem divider>
<ListItemText
primary="Username"
secondary={(data && data.username) || 'No username yet.'}
/>
</ListItem>
<ListItem divider>
<ListItemText
primary="Password"
secondary={(data && data.password.replace(/./g, '*')) || 'No password yet.'}
/>
</ListItem>
<ListItem divider>
<ListItemText
primary="Favorite Food"
secondary={(data && data.food) || 'No favorite food yet.'}
/>
</ListItem>
<ListItem divider>
<ListItemText primary="Email" secondary={(data && data.email) || 'No email yet.'} />
</ListItem>
<ListItem>
<ListItemText primary="Age" secondary={(data && data.age) || 'No age yet.'} />
</ListItem>
</List>
)
}