Style event form

This commit is contained in:
Amit Jakubowicz 2019-10-07 17:06:08 +02:00
parent 762f9aee9a
commit 41a6075326
14 changed files with 202 additions and 42 deletions

View File

@ -8,7 +8,7 @@
"build": "yarn client-build; yarn ssr-build",
"client-build": "(cd packages/qpa; yarn build)",
"ssr-build": "(cd packages/qpa-ssr; yarn build)",
"start": "NODE_ENV=development webpack-dev-server --config packages/qpa/webpack.config.ts --hot --progress",
"start": "(cd packages/qpa; yarn start)",
"ssr": "API_URL=http://alpha.quepasaalpujarra.com/graphql ts-node packages/qpa-ssr/index.ts",
"release": "docker build -t eu.gcr.io/qpa-staging-237606/web:$TAG .; docker push eu.gcr.io/qpa-staging-237606/web:$TAG",
"codegen": "gql2ts ./schema.graphql -o ./@types/graphql.d.ts"

View File

@ -0,0 +1,8 @@
{
"en": {
"APP_TITLE": "Evento en la Alpujarra"
},
"es": {
"APP_TITLE": "Events in the Alpujarra"
}
}

View File

@ -5,11 +5,30 @@ import * as React from "react"
import Footer from "./Footer"
import Header from "./Header/Header"
import Routes from "./Routes"
import * as intl from 'react-intl-universal'
import {Helmet} from 'react-helmet'
import AppMessages from './App.msg.json'
const App = () => (
<Root>
<Global
styles={css`
const App = () => {
const [intlInit, setIntlInit] = React.useState(false)
intl.init({
currentLocale: 'es-ES',
locales: {
'en-GB': AppMessages.en,
'es-ES': AppMessages.es
}
}).then(() => setIntlInit(true))
if (!intlInit) {
return null
}
return (
<Root>
<Helmet>
<title>{ intl.get('APP_TITLE')}</title>
</Helmet>
<Global
styles={css`
body {
margin: 0;
height: 100vh;
@ -18,16 +37,17 @@ const App = () => (
height: 100%;
}
`}
/>
<StyledHeader/>
<Content>
<Routes />
</Content>
<MessageCenterDisplay/>
<StyledFooter/>
</Root>
)
/>
<StyledHeader/>
<Content>
<Routes />
</Content>
<MessageCenterDisplay/>
<StyledFooter/>
</Root>
)
}
const Root = styled.div`
display: grid;
height: 100%;
@ -39,8 +59,7 @@ const Content = styled.div`
grid-row: body;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
justify-self: center;
`
const StyledFooter = styled(Footer)`

View File

@ -5,7 +5,7 @@ import MeQuery, { UserData } from "./MeQuery"
interface IAppContext {
me: UserData
isSSR: boolean
supportedLanguages: string[]
supportedLocales: string[]
}
interface Props {
@ -13,8 +13,8 @@ interface Props {
children: React.ReactChild
}
const SUPPORTED_LANGUAGES = ['en', 'es']
const AppContext = React.createContext<IAppContext>({ me: null, isSSR: false, supportedLanguages: SUPPORTED_LANGUAGES })
const SUPPORTED_LOCALES = ['en-GB', 'es-ES']
const AppContext = React.createContext<IAppContext>({ me: null, isSSR: false, supportedLocales: SUPPORTED_LOCALES })
const { Provider, Consumer } = AppContext
const AppContextProvider = (props: Props) => (
<MeQuery>
@ -29,7 +29,7 @@ const AppContextProvider = (props: Props) => (
<Provider value={{
me: data.me,
isSSR: props.isSSR,
supportedLanguages: SUPPORTED_LANGUAGES
supportedLocales: SUPPORTED_LOCALES
}}>
{
props.children

View File

@ -46,6 +46,7 @@ const Root = styled.div`
background: rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: row;
padding-right: 14px;
`
const LinksSection = styled.div`

View File

@ -6,7 +6,7 @@ import EventForm, {EventFormData} from "./EventForm"
const CreateEvent = () => {
const { addMessage } = useMessageCenter()
const { supportedLanguages } = useAppContext()
const { supportedLocales } = useAppContext()
return <CreateEventMutation onCompleted={() => {
addMessage({
@ -17,7 +17,7 @@ const CreateEvent = () => {
{
(createEvent, { loading }) => (
<EventForm
languages={supportedLanguages}
locales={supportedLocales}
loading={loading}
onSubmit={(values: EventFormData) => {
createEvent({

View File

@ -11,7 +11,7 @@ interface Props {
}
const EditEvent = (props: Props) => {
const { supportedLanguages } = useAppContext()
const { supportedLocales } = useAppContext()
return (
<EditEventMutation onCompleted={() => {
@ -33,7 +33,7 @@ const EditEvent = (props: Props) => {
return (
<EventForm
loading={editLoading}
languages={supportedLanguages}
locales={supportedLocales}
onSubmit={(values) => {
editEvent({
variables: {

View File

@ -0,0 +1,36 @@
{
"en": {
"EVENT_CREATED_SUCCESSFULLY": "Event was created successfully",
"EVENT_TITLE": "Title of event",
"DESCRIPTION": "Description of the event",
"DESCRIPTION_PLACEHOLDER": "Write a few words about your event",
"LOCATION": "Location",
"LOCATION_PLACEHOLDER": "Location's name",
"ADDRESS": "Address",
"ADDRESS_PLACEHOLDER": "Address of the location",
"EDIT": "Edit Event",
"CREATE": "Create Event",
"EVENT_FORM_INFO": "Event details in",
"en-GB": "English",
"es-ES": "Spanish",
"EVENT_FORM_DETAILS_FOREWORD": "Please enter some details about your event.",
"EVENT_FORM_DETAILS_FOREWORD_MULTILINGUAL": "Please enter some details about your event. Please consider that your audience is multilingual so please do make an effort to write the description in other languages too."
},
"es": {
"EVENT_CREATED_SUCCESSFULLY": "Evento ha sido creado correctamente",
"EVENT_TITLE": "Titulo del evento",
"DESCRIPTION": "Descripción del evento",
"DESCRIPTION_PLACEHOLDER": "Escribe unas palabras sobre tu evento",
"LOCATION": "Lugar",
"LOCATION_PLACEHOLDER": "Nombre del lugar",
"ADDRESS": "Dirección",
"ADDRESS_PLACEHOLDER": "Dirección del lugar",
"EDIT": "Modificar evento",
"CREATE": "Crear evento",
"EVENT_FORM_INFO": "Detalles del evento en",
"en-GB": "Inglés",
"es-ES": "Español",
"EVENT_FORM_DETAILS_FOREWORD": "Por favor, añade unos detalles sobre tu evento",
"EVENT_FORM_DETAILS_FOREWORD_MULTILINGUAL": "Por favor, añade unos detalles sobre tu evento. Ten en cuenta, que tu publico es multilingual así que por favor, haz el esfuerzo de escribir las descripciones en otros idiomas también"
}
}

View File

@ -1,3 +1,4 @@
import {css} from "@emotion/core"
import {addHours, format} from "date-fns"
import {Field, Form, Formik} from "formik"
import {Button} from "qpa-components"
@ -5,12 +6,14 @@ import * as React from "react"
import styled from "styled-components"
import {EventStatus} from "../../../@types"
import DateTime from "./DateTime"
import * as intl from 'react-intl-universal'
import messages from "./EventForm.msg.json"
interface Props {
values?: EventFormData
onSubmit: (values: EventFormData) => void
loading: boolean
languages: string[]
locales: string[]
}
export interface EventFormData {
@ -47,6 +50,10 @@ const nextWeekMidday = new Date(nextWeekTenAM)
nextWeekMidday.setUTCHours(12)
const EventForm = (props: Props) => {
intl.load({
'es-ES': messages.es,
'en-GB': messages.en
})
const isEdit = !!props.values
return (
<EventFormik
@ -60,7 +67,7 @@ const EventForm = (props: Props) => {
start: nextWeekTenAM.toISOString().substring(0, 16),
end: nextWeekMidday.toISOString().substring(0, 16),
},
infos: props.languages.map(lang => (
infos: props.locales.map(lang => (
{
language: lang,
title: "",
@ -82,22 +89,27 @@ const EventForm = (props: Props) => {
>
{({isValid, setFieldValue, values}) => (
<StyledForm>
<FormTitle>
{
props.locales.length > 1 ? intl.get('EVENT_FORM_DETAILS_FOREWORD_MULTILINGUAL') : intl.get('EVENT_FORM_DETAILS_FOREWORD')
}
</FormTitle>
{
props.languages.map(lang => {
props.locales.map(lang => {
const i = values.infos.findIndex(info => info.language === lang)
return (
<section key={lang}>
<h1>{lang}</h1>
<p>Title</p>
<h1>{intl.get('EVENT_FORM_INFO')} {intl.get(lang)}</h1>
<p>{intl.get('EVENT_TITLE')}</p>
<Field name={`info[${i}].title`}>
{({field}) => <input {...field} placeholder="Name your event"/>}
</Field>
<p>Description</p>
<p>{intl.get('DESCRIPTION')}</p>
<Field name={`info[${i}].description`}>
{({field}) => (
<textarea
{...field}
placeholder="Write a few words about your event"
placeholder={intl.get('DESCRIPTION_PLACEHOLDER')}
/>
)}
</Field>
@ -126,20 +138,36 @@ const EventForm = (props: Props) => {
)
}
</Field>
<p>Location</p>
<p>{intl.get('LOCATION')}</p>
<Field name="location.name">
{({field}) => <input {...field} placeholder="Location's name"/>}
{({field}) => <input {...field} placeholder={intl.get('LOCATION_PLACEHOLDER')}/>}
</Field>
<p>Address</p>
<p>{intl.get('ADDRESS')}</p>
<Field name="location.address">
{({field}) => <input {...field} placeholder="Address"/>}
{({field}) => <input {...field} placeholder={intl.get('ADDRESS_PLACEHOLDER')}/>}
</Field>
<Button type="submit" loading={props.loading}>{isEdit ? "Edit" : "Create"}</Button>
<Button type="submit"
loading={props.loading}>{isEdit ? intl.get('EDIT') : intl.get('CREATE')}</Button>
</StyledForm>
)}
</EventFormik>
)
}
const StyledForm = styled(Form)``
const FormTitle = styled.div`
font-size: 24px;
`
const StyledForm = styled(Form)`
display: flex;
flex-direction: column;
margin-top: 24px;
width: 800px;
@media(max-width: 800px) {
width: 600px;
}
@media(max-width: 600px) {
width: 450px;
}
`
export default EventForm

View File

@ -40,6 +40,8 @@
"react": "^16.8.6",
"react-apollo": "^2.2.4",
"react-dom": "^16.8.6",
"react-helmet": "^5.2.1",
"react-intl-universal": "^2.1.4",
"react-router": "^5.0.0",
"react-router-dom": "^5.0.0",
"styled-components": "^4.1.3",

View File

@ -3,6 +3,7 @@
"skipLibCheck": true,
"sourceMap": true,
"jsx": "react",
"resolveJsonModule": true,
"lib": [
"es7",
"esnext.asynciterable"

View File

@ -67,7 +67,6 @@ const config: webpack.Configuration = {
publicPath: "/",
},
plugins: [new HtmlWebpackPlugin({
title: "blabla",
template: "./index-dev.html",
})],

View File

@ -3,6 +3,8 @@
"skipLibCheck": true,
"sourceMap": true,
"jsx": "react",
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": [
"es7",
"esnext.asynciterable",

View File

@ -2807,6 +2807,11 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0:
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
console-polyfill@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/console-polyfill/-/console-polyfill-0.3.0.tgz#84900902a18c47a5eba932be75fa44d23e8af861"
integrity sha512-w+JSDZS7XML43Xnwo2x5O5vxB0ID7T5BdqDtyqT6uiCAX2kZAgcWxNaGqT97tZfSHzfOcvrfsDAodKcJ3UvnXQ==
constant-case@^1.1.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-1.1.2.tgz#8ec2ca5ba343e00aa38dbf4e200fd5ac907efd63"
@ -2849,6 +2854,11 @@ cookie@0.4.0:
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
cookie@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
copy-concurrently@^1.0.0:
version "1.0.5"
resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0"
@ -3513,7 +3523,7 @@ es-to-primitive@^1.2.0:
is-date-object "^1.0.1"
is-symbol "^1.0.2"
escape-html@~1.0.3:
escape-html@^1.0.3, escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
@ -4608,6 +4618,23 @@ interpret@1.2.0:
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296"
integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==
intl-messageformat-parser@1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-1.4.0.tgz#b43d45a97468cadbe44331d74bb1e8dea44fc075"
integrity sha1-tD1FqXRoytvkQzHXS7Ho3qRPwHU=
intl-messageformat@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-2.2.0.tgz#345bcd46de630b7683330c2e52177ff5eab484fc"
integrity sha1-NFvNRt5jC3aDMwwuUhd/9eq0hPw=
dependencies:
intl-messageformat-parser "1.4.0"
intl@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/intl/-/intl-1.2.5.tgz#82244a2190c4e419f8371f5aa34daa3420e2abde"
integrity sha1-giRKIZDE5Bn4Nx9ao02qNCDiq94=
invariant@^2.2.2, invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
@ -5590,6 +5617,11 @@ lodash.isequal@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
lodash.merge@^4.6.1:
version "4.6.2"
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
lodash.sortby@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
@ -6871,7 +6903,7 @@ querystring-es3@^0.2.0:
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=
querystring@0.2.0:
querystring@0.2.0, querystring@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
@ -6949,11 +6981,21 @@ react-dom@^16.8.6:
prop-types "^15.6.2"
scheduler "^0.13.6"
react-fast-compare@^2.0.1:
react-fast-compare@^2.0.1, react-fast-compare@^2.0.2:
version "2.0.4"
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9"
integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==
react-helmet@^5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-5.2.1.tgz#16a7192fdd09951f8e0fe22ffccbf9bb3e591ffa"
integrity sha512-CnwD822LU8NDBnjCpZ4ySh8L6HYyngViTZLfBBb3NjtrpN8m49clH8hidHouq20I51Y6TpCTISCBbqiY5GamwA==
dependencies:
object-assign "^4.1.1"
prop-types "^15.5.4"
react-fast-compare "^2.0.2"
react-side-effect "^1.1.0"
react-hot-loader@^4.8.2:
version "4.12.10"
resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.12.10.tgz#b3457c0f733423c4827c6d2672e50c9f8bedaf6b"
@ -6968,6 +7010,21 @@ react-hot-loader@^4.8.2:
shallowequal "^1.1.0"
source-map "^0.7.3"
react-intl-universal@^2.1.4:
version "2.1.4"
resolved "https://registry.yarnpkg.com/react-intl-universal/-/react-intl-universal-2.1.4.tgz#3111e77debc8f12f747be4e869b804ca5d90bfdf"
integrity sha512-KRE8cy9sw6spkgIAjAlnu34fzgDM4n4OAyTXaNUUAohxQhQlMswKlDpsCQDR+cv1RQiO8KoxhcQtjnQ7+DRoNA==
dependencies:
console-polyfill "^0.3.0"
cookie "^0.3.1"
escape-html "^1.0.3"
intl "^1.2.5"
intl-messageformat "^2.2.0"
invariant "^2.2.2"
lodash.merge "^4.6.1"
object-keys "^1.0.11"
querystring "^0.2.0"
react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4:
version "16.8.6"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16"
@ -7007,6 +7064,13 @@ react-router@5.0.1, react-router@^5.0.0:
tiny-invariant "^1.0.2"
tiny-warning "^1.0.0"
react-side-effect@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-1.2.0.tgz#0e940c78faba0c73b9b0eba9cd3dda8dfb7e7dae"
integrity sha512-v1ht1aHg5k/thv56DRcjw+WtojuuDHFUgGfc+bFHOWsF4ZK6C2V57DO0Or0GPsg6+LSTE0M6Ry/gfzhzSwbc5w==
dependencies:
shallowequal "^1.0.1"
react@^16.8.6:
version "16.8.6"
resolved "https://registry.yarnpkg.com/react/-/react-16.8.6.tgz#ad6c3a9614fd3a4e9ef51117f54d888da01f2bbe"
@ -7540,7 +7604,7 @@ sha.js@^2.4.0, sha.js@^2.4.8:
inherits "^2.0.1"
safe-buffer "^5.0.1"
shallowequal@^1.1.0:
shallowequal@^1.0.1, shallowequal@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==