diff --git a/package.json b/package.json index a6597a4..b40f191 100644 --- a/package.json +++ b/package.json @@ -3,10 +3,11 @@ "version": "0.1.0", "private": true, "dependencies": { - "bootstrap": "4.3.1", - "flag-icons": "^6.6.6", - "i18next": "^22.4.10", - "i18next-browser-languagedetector": "^7.0.1", + "@fortawesome/fontawesome-free": "^6.3.0", + "@fortawesome/fontawesome-svg-core": "^6.3.0", + "@fortawesome/free-regular-svg-icons": "^6.3.0", + "@fortawesome/free-solid-svg-icons": "^6.3.0", + "@fortawesome/react-fontawesome": "^0.2.0", "@js-joda/core": "^5.5.2", "@js-joda/timezone": "^2.17.2", "@types/jest": "^27.5.2", @@ -14,17 +15,24 @@ "@types/node": "^16.11.68", "@types/react": "^18.0.21", "@types/react-dom": "^18.0.6", + "bootstrap": "^5.2.3", + "flag-icons": "^6.6.6", + "i18next": "^22.4.10", + "i18next-browser-languagedetector": "^7.0.1", "jquery": "^3.6.1", + "legacy-bootstrap": "npm:bootstrap@4.4.1", + "legacy-fontawesome": "npm:@fortawesome/fontawesome-free@5.13.0", "react": "^18.2.0", "react-bootstrap": "^2.7.2", + "react-datepicker": "^4.10.0", "react-dom": "^18.2.0", + "react-form-builder2": "^0.14.3", "react-i18next": "^12.1.5", "react-router-bootstrap": "^0.26.2", - "react-form-builder2": "^0.14.2", "react-router-dom": "^6.4.3", "react-scripts": "5.0.1", - "styled-components": "^5.3.6", "react-spinners": "^0.13.6", + "styled-components": "^5.3.6", "typescript": "^4.8.4" }, "scripts": { @@ -67,6 +75,7 @@ "@types/jest": "^27.5.2", "@types/node": "^16.11.68", "@types/react": "^18.0.21", + "@types/react-datepicker": "^4.10.0", "@types/react-dom": "^18.0.6", "@types/react-router-bootstrap": "^0.26.0", "@types/styled-components": "^5.1.26", diff --git a/public/index.html b/public/index.html index 524233e..7c0f712 100644 --- a/public/index.html +++ b/public/index.html @@ -18,10 +18,6 @@ media="all" /> Asteriski - Tapahtumailmoittautumisjärjestelmä - diff --git a/src/components/BasicInformationForm.tsx b/src/components/BasicInformationForm.tsx new file mode 100644 index 0000000..f59f358 --- /dev/null +++ b/src/components/BasicInformationForm.tsx @@ -0,0 +1,214 @@ +import React, { useState } from 'react' +import { Quota } from '../types/types' +import { Form, Row, Col, Button } from 'react-bootstrap' +import DatePicker from 'react-datepicker' +import 'react-datepicker/dist/react-datepicker.css' +import { QuotaModal } from './QuotaModal' +import { EventBasicInformation } from '../types/types' + +export const BasicInformationForm = ({ + onSubmit, +}: { + onSubmit: (data: EventBasicInformation) => void +}) => { + const [modalVisible, setModalVisible] = useState(false) + const [quotas, setQuotas] = useState([]) + const [name, setName] = useState('') + const [place, setPlace] = useState('') + const [description, setDescription] = useState('') + const [price, setPrice] = useState('') + const [startDate, setStartDate] = useState() + const [endDate, setEndDate] = useState() + const [signupStarts, setSignupStarts] = useState() + const [signupEnds, setSignupEnds] = useState() + const [image, setImage] = useState(null) + const [maxParticipants, setMaxParticipants] = useState('') + const [hasParticipantLimit, setHasParticipantLimit] = useState(false) + const [hasQuotas, setHasQuotas] = useState(false) + + return ( +
+ + Tapahtuman nimi + setName(e.target.value)} + /> + + + + Tapahtuman paikka + setPlace(e.target.value)} + /> + + + Tapahtuman kuvaus + setDescription(e.target.value)} + /> + + + Tapahtuman hinta + setPrice(e.target.value)} + /> + + + + + Tapahtuman aloituspäivä + setStartDate(date)} + showTimeSelect + timeFormat="HH:mm" + dateFormat="dd.M.yyyy HH:mm" + /> + + + Tapahtuman lopetuspäivä + setEndDate(date)} + showTimeSelect + timeFormat="HH:mm" + dateFormat="dd.M.yyyy HH:mm" + /> + + + + + + + Ilmoittautumisen aloituspäivä + setSignupStarts(date)} + showTimeSelect + timeFormat="HH:mm" + dateFormat="dd.M.yyyy HH:mm" + /> + + + Ilmoittautumisen lopetuspäivä + setSignupEnds(date)} + showTimeSelect + timeFormat="HH:mm" + dateFormat="dd.M.yyyy HH:mm" + /> + + + + + ) => { + if (e.target.files) setImage(e.target.files[0]) + }} + /> + + + + + setHasParticipantLimit(e.target.checked)} + /> + + {hasParticipantLimit && ( + + Maksimi osallistujamäärä + setMaxParticipants(e.target.value)} + /> + + )} + + + + + + + setHasQuotas(e.target.checked)} + /> + + {hasQuotas && ( + + Osallistujakiintiöt + `${group || ''}: ${quota || ''}`) + .join('\n')} + /> + + setModalVisible(false)} + onSubmit={(quotas) => setQuotas(quotas)} + /> + + )} + + + + + +
+ ) +} + +const parseDate = (date?: Date) => date?.toDateString() || undefined diff --git a/src/components/FormBuilder.tsx b/src/components/FormBuilder.tsx new file mode 100644 index 0000000..95e7835 --- /dev/null +++ b/src/components/FormBuilder.tsx @@ -0,0 +1,31 @@ +import React, { useState } from 'react' +import { + ReactFormBuilder, + ReactFormGenerator, + FormBuilderPostData, +} from 'react-form-builder2' +import 'legacy-bootstrap/dist/css/bootstrap.min.css' // :( +import 'legacy-fontawesome/css/all.min.css' // :`( +import 'react-form-builder2/dist/app.css' + +const FormBuilder = () => { + const [data, setData] = useState(null) + return ( + <> + + { + console.log(a) + setData(a) + }} + /> + + ) +} + +export { FormBuilder } diff --git a/src/components/HeaderComponent.tsx b/src/components/HeaderComponent.tsx index 2d1fd20..039d3b1 100644 --- a/src/components/HeaderComponent.tsx +++ b/src/components/HeaderComponent.tsx @@ -94,6 +94,7 @@ const StyledHeaderContainer = styled.div` const StyledNavbar = styled(Navbar)` background-color: #2b8c49; box-shadow: 0 0 0.7em #8e8d8d; + padding: 0.5rem 1rem; ` const StyledLink = styled(Nav.Link)` diff --git a/src/components/QuotaModal.tsx b/src/components/QuotaModal.tsx new file mode 100644 index 0000000..6fdceec --- /dev/null +++ b/src/components/QuotaModal.tsx @@ -0,0 +1,105 @@ +import React, { useState } from 'react' +import { Modal, Button, Form, Row, Col } from 'react-bootstrap' +import { Quota } from '../types/types' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' + +import { faTrashCan } from '@fortawesome/free-regular-svg-icons' +import { faPlus } from '@fortawesome/free-solid-svg-icons' + +export const QuotaModal = ({ + visible, + onHide, + onSubmit, +}: { + visible: boolean + onHide: () => void + onSubmit: (quotas: Quota[]) => void +}) => { + const [quotas, setQuotas] = useState([{ group: '', quota: '' }]) + return ( +
+ + + Osallistujakiintiöt + + + +
+ {quotas.map(({ group, quota }, index) => ( + + + + + setQuotas( + quotas.map((quota, i) => + index === i + ? { ...quota, group: e.target.value } + : quota + ) + ) + } + /> + + + + setQuotas( + quotas.map((quota, i) => + index === i + ? { group, quota: e.target.value } + : quota + ) + ) + } + /> + + + + {' '} + + + ))} +
+ +
+ + + + + +
+
+ ) +} diff --git a/src/stories/BasicInformationForm.stories.tsx b/src/stories/BasicInformationForm.stories.tsx new file mode 100644 index 0000000..a8de9ef --- /dev/null +++ b/src/stories/BasicInformationForm.stories.tsx @@ -0,0 +1,23 @@ +import React from 'react' +import { ComponentStory, ComponentMeta } from '@storybook/react' + +import { BasicInformationForm } from '../components/BasicInformationForm' +import 'bootstrap/dist/css/bootstrap.min.css' +import '../translations/i18n' + +export default { + title: 'BasicInformationForm', + component: BasicInformationForm, + parameters: { + // More on Story layout: https://storybook.js.org/docs/react/configure/story-layout + layout: 'fullscreen', + }, +} as ComponentMeta + +const Template: ComponentStory = () => ( +
+ console.log(e)} /> +
+) + +export const Form = Template.bind({}) diff --git a/src/stories/Modal.stories.tsx b/src/stories/Modal.stories.tsx new file mode 100644 index 0000000..41098ef --- /dev/null +++ b/src/stories/Modal.stories.tsx @@ -0,0 +1,26 @@ +import React from 'react' +import { ComponentStory, ComponentMeta } from '@storybook/react' + +import { QuotaModal } from '../components/QuotaModal' + +import 'bootstrap/dist/css/bootstrap.min.css' +import '../translations/i18n' + +export default { + title: 'Modal', + component: QuotaModal, + parameters: { + // More on Story layout: https://storybook.js.org/docs/react/configure/story-layout + layout: 'fullscreen', + }, +} as ComponentMeta + +const Template: ComponentStory = (args) => ( + console.log('hide')} + onSubmit={(quotas) => console.log(quotas)} + /> +) + +export const Modal = Template.bind({}) diff --git a/src/types/types.ts b/src/types/types.ts index e77f3cd..ecab0a9 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -1,4 +1,5 @@ import { components } from '@asteriskiry/eventsignup_backend-types/' export type Event = components['schemas']['Event'] +export type EventBasicInformation = Omit export type Quota = components['schemas']['Quota']