FC Admin object creation pages
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import "./DatetimeWidget.scss";
|
||||
|
||||
export interface DatetimeWidgetProps {
|
||||
interface DatetimeWidgetProps {
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
onFocus: () => void;
|
||||
@@ -9,42 +9,37 @@ export interface DatetimeWidgetProps {
|
||||
required: boolean;
|
||||
disabled: boolean;
|
||||
}
|
||||
export interface DatetimeWidgetState { }
|
||||
|
||||
class DatetimeWidget extends React.Component<DatetimeWidgetProps, DatetimeWidgetState> {
|
||||
render() {
|
||||
const { value, onChange, onFocus, onBlur, required, disabled } = this.props;
|
||||
|
||||
let date;
|
||||
let time;
|
||||
if (value && value.length !== 0) {
|
||||
let rest;
|
||||
[date, rest] = value.split("T");
|
||||
time = rest.slice(0, 5);
|
||||
}
|
||||
|
||||
const commonProps = {
|
||||
onFocus,
|
||||
onBlur,
|
||||
required,
|
||||
disabled,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="datetime-widget">
|
||||
<input
|
||||
type="date"
|
||||
onChange={(event) => onChange(`${event.target.value}T${time}`)}
|
||||
value={date}
|
||||
{...commonProps} />
|
||||
<input
|
||||
type="time"
|
||||
onChange={(event) => onChange(`${date}T${event.target.value}:00`)}
|
||||
value={time}
|
||||
{...commonProps} />
|
||||
</div>
|
||||
);
|
||||
const DatetimeWidget: React.FC<DatetimeWidgetProps> = ({ value, onChange, onFocus, onBlur, required, disabled }) => {
|
||||
let date;
|
||||
let time;
|
||||
if (value && value.length !== 0) {
|
||||
let rest;
|
||||
[date, rest] = value.split("T");
|
||||
time = rest.slice(0, 5);
|
||||
}
|
||||
|
||||
const commonProps = {
|
||||
onFocus,
|
||||
onBlur,
|
||||
required,
|
||||
disabled,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="datetime-widget">
|
||||
<input
|
||||
type="date"
|
||||
onChange={(event) => onChange(`${event.target.value}T${time}`)}
|
||||
value={date}
|
||||
{...commonProps} />
|
||||
<input
|
||||
type="time"
|
||||
onChange={(event) => onChange(`${date}T${event.target.value}:00`)}
|
||||
value={time}
|
||||
{...commonProps} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default DatetimeWidget;
|
||||
|
||||
@@ -3,10 +3,9 @@ import "./SectionDividerWidget.scss";
|
||||
import Icon from "../../Icon";
|
||||
import { IconType } from "../../Icon/Icon";
|
||||
|
||||
export interface SectionDividerWidgetProps {
|
||||
interface SectionDividerWidgetProps {
|
||||
label: string;
|
||||
}
|
||||
export interface SectionDividerWidgetState { }
|
||||
|
||||
const getIconByLabel = (label: string) => {
|
||||
if (label === "Finnish") {
|
||||
@@ -19,16 +18,10 @@ const getIconByLabel = (label: string) => {
|
||||
return null;
|
||||
}
|
||||
|
||||
class SectionDividerWidget extends React.Component<SectionDividerWidgetProps, SectionDividerWidgetState> {
|
||||
render() {
|
||||
const { label } = this.props;
|
||||
|
||||
return (
|
||||
<h3 className="section-divider-widget">
|
||||
{label} {getIconByLabel(label)}
|
||||
</h3>
|
||||
);
|
||||
}
|
||||
}
|
||||
const SectionDividerWidget: React.FC<SectionDividerWidgetProps> = ({ label }) => (
|
||||
<h3 className="section-divider-widget">
|
||||
{label} {getIconByLabel(label)}
|
||||
</h3>
|
||||
);
|
||||
|
||||
export default SectionDividerWidget;
|
||||
|
||||
@@ -6,23 +6,21 @@ import AddIcon from "@assets/img/add-icon.png";
|
||||
import "./SignupQuestionsWidget.scss";
|
||||
import QuestionList from "./QuestionList";
|
||||
|
||||
export interface SignupQuestionsWidgetProps {
|
||||
interface SignupQuestionsWidgetProps {
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
onFocus: () => void;
|
||||
required: boolean;
|
||||
disabled: boolean;
|
||||
}
|
||||
export interface SignupQuestionsWidgetState { }
|
||||
|
||||
class SignupQuestionsWidget extends React.Component<SignupQuestionsWidgetProps, SignupQuestionsWidgetState> {
|
||||
onValueChange = (questions: Question[]) => {
|
||||
const { onChange } = this.props;
|
||||
const SignupQuestionsWidget: React.FC<SignupQuestionsWidgetProps> = ({ value, onFocus, onChange }) => {
|
||||
const onValueChange = (questions: Question[]) => {
|
||||
const newValue = JSON.stringify(questions);
|
||||
onChange(newValue);
|
||||
}
|
||||
|
||||
handleNewRowClick = (questions) => () => {
|
||||
const handleNewRowClick = (questions) => () => {
|
||||
const newRow: Question = {
|
||||
id: shortid.generate(),
|
||||
name: `Question #${questions.length + 1}`,
|
||||
@@ -31,47 +29,42 @@ class SignupQuestionsWidget extends React.Component<SignupQuestionsWidgetProps,
|
||||
};
|
||||
const newQuestions: Question[] = questions.concat([newRow]);
|
||||
|
||||
this.onValueChange(newQuestions);
|
||||
onValueChange(newQuestions);
|
||||
}
|
||||
|
||||
handleDragEnd = (questions: Question[]) => (result) => {
|
||||
const handleDragEnd = (questions: Question[]) => (result) => {
|
||||
const srcIndex = result.source.index;
|
||||
const dstIndex = result.destination.index;
|
||||
const srcCopy = { ...questions[srcIndex] };
|
||||
questions.splice(srcIndex, 1);
|
||||
questions.splice(dstIndex, 0, srcCopy);
|
||||
|
||||
this.onValueChange(questions);
|
||||
onValueChange(questions);
|
||||
}
|
||||
const questions = JSON.parse(value) as Question[];
|
||||
|
||||
render() {
|
||||
const { value, onFocus } = this.props;
|
||||
|
||||
const questions = JSON.parse(value) as Question[];
|
||||
|
||||
return (
|
||||
<div className="signup-questions-widget">
|
||||
<DragDropContext
|
||||
onDragEnd={this.handleDragEnd(questions)}
|
||||
onDragStart={onFocus}
|
||||
>
|
||||
<Droppable droppableId="questions">
|
||||
{(provided) => (
|
||||
<QuestionList
|
||||
{...provided.droppableProps}
|
||||
innerRef={provided.innerRef}
|
||||
questions={questions}
|
||||
onChange={this.onValueChange}
|
||||
placeholder={provided.placeholder} />
|
||||
)}
|
||||
</Droppable>
|
||||
</DragDropContext>
|
||||
<button type="button" className="add-link" onClick={this.handleNewRowClick(questions)}>
|
||||
<img src={AddIcon} /> New Question
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className="signup-questions-widget">
|
||||
<DragDropContext
|
||||
onDragEnd={handleDragEnd(questions)}
|
||||
onDragStart={onFocus}
|
||||
>
|
||||
<Droppable droppableId="questions">
|
||||
{(provided) => (
|
||||
<QuestionList
|
||||
{...provided.droppableProps}
|
||||
innerRef={provided.innerRef}
|
||||
questions={questions}
|
||||
onChange={onValueChange}
|
||||
placeholder={provided.placeholder} />
|
||||
)}
|
||||
</Droppable>
|
||||
</DragDropContext>
|
||||
<button type="button" className="add-link" onClick={handleNewRowClick(questions)}>
|
||||
<img src={AddIcon} /> New Question
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SignupQuestionsWidget;
|
||||
|
||||
+2
-1
@@ -1,11 +1,12 @@
|
||||
import axios from "axios";
|
||||
import { getAuthHeader } from "@utils/auth";
|
||||
import { Tag } from "./Tag";
|
||||
|
||||
const url = `${process.env.API_URL}/feed/`;
|
||||
|
||||
export interface Post {
|
||||
id: number;
|
||||
tags: number[];
|
||||
tags: Tag[];
|
||||
visible: boolean;
|
||||
image: string;
|
||||
title_fi: string;
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import Form, { ISubmitEvent, IChangeEvent, ErrorSchema } from "react-jsonschema-form";
|
||||
import { colors }from "@theme/colors";
|
||||
import { Event } from "@models/Event";
|
||||
import { Post } from "@models/Feed";
|
||||
import { SignupForm } from "@models/SignupForm";
|
||||
import { JobAd } from "@models/JobAd";
|
||||
|
||||
const AdminCreateCommon = styled.main`
|
||||
const Common = styled.main`
|
||||
width: 100%;
|
||||
|
||||
fieldset {
|
||||
@@ -54,4 +60,65 @@ const AdminCreateCommon = styled.main`
|
||||
}
|
||||
`;
|
||||
|
||||
type FormTypes = Event | SignupForm | Post | JobAd;
|
||||
|
||||
type AdminCreateCommonProps = {
|
||||
title: string;
|
||||
formData?: FormTypes;
|
||||
schema: {
|
||||
[name: string]: any;
|
||||
};
|
||||
UISchema: {
|
||||
[name: string]: any;
|
||||
};
|
||||
onChange: (e: IChangeEvent<FormTypes>, es?: ErrorSchema) => any;
|
||||
onFocus: (id: string, value: string | number | boolean) => void;
|
||||
onSubmit: (e: ISubmitEvent<FormTypes>) => any;
|
||||
statusMessage: string;
|
||||
error: string;
|
||||
widgets: {
|
||||
[name: string]: any;
|
||||
};
|
||||
}
|
||||
|
||||
const AdminCreateCommon: React.FC<AdminCreateCommonProps> = ({
|
||||
title,
|
||||
formData,
|
||||
schema,
|
||||
UISchema,
|
||||
onChange,
|
||||
onFocus,
|
||||
onSubmit,
|
||||
statusMessage,
|
||||
error,
|
||||
widgets
|
||||
}) => {
|
||||
|
||||
const onError = (data: any) => {
|
||||
console.error("error, data:");
|
||||
console.log(data);
|
||||
}
|
||||
|
||||
return (
|
||||
<Common>
|
||||
<h1>{title}</h1>
|
||||
{statusMessage && <div className="success">{statusMessage}</div>}
|
||||
<Form
|
||||
schema={schema}
|
||||
uiSchema={UISchema}
|
||||
formData={formData}
|
||||
idPrefix="rjsf"
|
||||
widgets={widgets}
|
||||
onChange={onChange}
|
||||
onSubmit={onSubmit}
|
||||
onError={onError}
|
||||
onFocus={onFocus} />
|
||||
|
||||
{error && (
|
||||
<div className="error">{error}</div>
|
||||
)}
|
||||
</Common>
|
||||
)
|
||||
}
|
||||
|
||||
export default AdminCreateCommon;
|
||||
|
||||
+202
-283
@@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Helmet } from "react-helmet";
|
||||
import Form from "react-jsonschema-form";
|
||||
import { RouteComponentProps } from "react-router-dom";
|
||||
import AdminCreateCommon from "./AdminCreateCommon";
|
||||
import { Tag, getTags } from "@models/Tag";
|
||||
import { SignupForm, getForms } from "@models/SignupForm";
|
||||
@@ -16,89 +16,184 @@ const widgets = {
|
||||
markdownEditor: MarkdownEditorWidget
|
||||
};
|
||||
|
||||
export interface EventCreatePageProps {
|
||||
history: {
|
||||
push: (to: string) => void;
|
||||
const buildSchema = (formData: Event, signupForms: SignupForm[], tags: Tag[]) => {
|
||||
const date = new Date(), tomorrowDate = new Date();
|
||||
const currentDatetime = date.toISOString();
|
||||
tomorrowDate.setDate(tomorrowDate.getDate() + 1);
|
||||
const tomorrowDatetime = tomorrowDate.toISOString();
|
||||
|
||||
const schema = {
|
||||
title: formData?.id ? formData.title_fi : "New Event",
|
||||
type: "object",
|
||||
required: ["title_fi", "title_en", "tags", "location_fi", "location_en", "start_time", "end_time", "description_fi", "description_en", "content_fi", "content_en"],
|
||||
properties: {
|
||||
tags: {
|
||||
type: "array",
|
||||
title: "Event tags",
|
||||
items: {
|
||||
type: "number",
|
||||
enum: tags.map(t => t.id),
|
||||
enumNames: tags.map(t => t.name_fi),
|
||||
},
|
||||
uniqueItems: true,
|
||||
default: [],
|
||||
},
|
||||
visible: {
|
||||
type: "boolean",
|
||||
title: "Visible",
|
||||
default: true,
|
||||
},
|
||||
start_time: {
|
||||
type: "string",
|
||||
title: "Start time",
|
||||
default: currentDatetime,
|
||||
},
|
||||
end_time: {
|
||||
type: "string",
|
||||
title: "End time",
|
||||
default: tomorrowDatetime,
|
||||
},
|
||||
signupForm: {
|
||||
type: "array",
|
||||
title: "Signup forms",
|
||||
items: {
|
||||
type: "number",
|
||||
// TODO: A bug here, DB must have at least one SignupForm, otherwise cannot submit
|
||||
enum: signupForms.map(form => form.id),
|
||||
enumNames: signupForms.map(form => form.title_fi),
|
||||
},
|
||||
uniqueItems: true,
|
||||
},
|
||||
image: {
|
||||
type: ["string", "null"],
|
||||
format: formData?.image ? "uri-reference" : "data-url",
|
||||
title: "Override tag icon with image",
|
||||
default: undefined
|
||||
},
|
||||
finnish_section_divider: {
|
||||
title: "Finnish",
|
||||
type: "string",
|
||||
},
|
||||
title_fi: {
|
||||
type: "string",
|
||||
title: "Title",
|
||||
default: ""
|
||||
},
|
||||
description_fi: {
|
||||
type: "string",
|
||||
title: "Description",
|
||||
default: "",
|
||||
},
|
||||
content_fi: {
|
||||
type: "string",
|
||||
title: "Content",
|
||||
default: "",
|
||||
},
|
||||
location_fi: {
|
||||
type: "string",
|
||||
title: "Location",
|
||||
default: "",
|
||||
},
|
||||
english_section_divider: {
|
||||
title: "English",
|
||||
type: "string",
|
||||
},
|
||||
title_en: {
|
||||
type: "string",
|
||||
title: "Title",
|
||||
default: ""
|
||||
},
|
||||
description_en: {
|
||||
type: "string",
|
||||
title: "Description",
|
||||
default: "",
|
||||
},
|
||||
content_en: {
|
||||
type: "string",
|
||||
title: "Content",
|
||||
default: "",
|
||||
},
|
||||
location_en: {
|
||||
type: "string",
|
||||
title: "Location",
|
||||
default: "",
|
||||
},
|
||||
}
|
||||
};
|
||||
match: {
|
||||
params: {
|
||||
id?: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
export interface EventCreatePageState {
|
||||
tags: Tag[];
|
||||
signupForm: SignupForm[];
|
||||
error?: string;
|
||||
statusMessage?: string;
|
||||
formData: Event;
|
||||
return schema;
|
||||
}
|
||||
|
||||
class EventCreatePage extends React.Component<EventCreatePageProps, EventCreatePageState> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
tags: [],
|
||||
signupForm: [],
|
||||
formData: {} as Event,
|
||||
};
|
||||
const buildUISchema = () => {
|
||||
const uiSchema = {
|
||||
content_fi: {
|
||||
"ui:widget": "markdownEditor",
|
||||
},
|
||||
content_en: {
|
||||
"ui:widget": "markdownEditor",
|
||||
},
|
||||
start_time: {
|
||||
"ui:widget": "datetime",
|
||||
},
|
||||
end_time: {
|
||||
"ui:widget": "datetime",
|
||||
},
|
||||
image: {
|
||||
"ui:options": {
|
||||
accept: [".jpg", ".jpeg", ".png"]
|
||||
}
|
||||
},
|
||||
finnish_section_divider: {
|
||||
"ui:widget": "section_divider",
|
||||
"ui:options": {
|
||||
label: false
|
||||
},
|
||||
},
|
||||
english_section_divider: {
|
||||
"ui:widget": "section_divider",
|
||||
"ui:options": {
|
||||
label: false
|
||||
},
|
||||
},
|
||||
};
|
||||
return uiSchema;
|
||||
}
|
||||
|
||||
this.fetchTags();
|
||||
this.fetchSignupForms();
|
||||
interface MatchParams {
|
||||
id?: string;
|
||||
}
|
||||
|
||||
const { id } = props.match.params;
|
||||
if (id !== undefined) {
|
||||
this.fetchInitialFormData(id);
|
||||
type EventCreatePageProps = RouteComponentProps<MatchParams>;
|
||||
|
||||
const EventCreatePage: React.FC<EventCreatePageProps> = ({ match: { params: { id } } }) => {
|
||||
const [formData, setFormData] = useState<Event>(null);
|
||||
const [tags, setTags] = useState<Tag[]>([]);
|
||||
const [signupForms, setSignupForms] = useState<SignupForm[]>([]);
|
||||
const [error, setError] = useState<string>(null);
|
||||
const [statusMessage, setStatusMessage] = useState<string>(null);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
getTags()
|
||||
.then(res => setTags(res))
|
||||
.catch(err => setError(err))
|
||||
|
||||
getForms(true)
|
||||
.then(res => setSignupForms(res))
|
||||
.catch(err => setError(err))
|
||||
|
||||
const eventId = id && Number(id);
|
||||
if (eventId !== undefined) {
|
||||
getEvent(eventId, true)
|
||||
.then(res => setFormData({
|
||||
...res,
|
||||
tags: (res.tags).map(inst => inst.id) as any,
|
||||
signupForm: (res.signupForm).map(inst => inst.id) as any,
|
||||
}))
|
||||
.catch(err => setError(err))
|
||||
}
|
||||
}
|
||||
}, [id])
|
||||
|
||||
fetchInitialFormData = async (id) => {
|
||||
try {
|
||||
const data = await getEvent(id, true);
|
||||
data.tags = (data.tags as any).map(inst => inst.id);
|
||||
data.signupForm = (data.signupForm as any).map(inst => inst.id);
|
||||
this.setState({
|
||||
formData: data,
|
||||
});
|
||||
} catch (err) {
|
||||
this.setState({
|
||||
error: String(err),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fetchTags = async () => {
|
||||
try {
|
||||
const tags = await getTags();
|
||||
this.setState({
|
||||
tags,
|
||||
});
|
||||
return tags;
|
||||
} catch (err) {
|
||||
this.setState({
|
||||
error: String(err),
|
||||
});
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
fetchSignupForms = async () => {
|
||||
try {
|
||||
const signupForm = await getForms(true);
|
||||
this.setState({
|
||||
signupForm
|
||||
})
|
||||
return signupForm;
|
||||
} catch (err) {
|
||||
this.setState({
|
||||
error: String(err),
|
||||
});
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
onSubmit = async (data) => {
|
||||
const { history } = this.props;
|
||||
const onSubmit = async (data) => {
|
||||
try {
|
||||
const payload = data.formData;
|
||||
payload.signup_id = payload.signupForm;
|
||||
@@ -113,10 +208,8 @@ class EventCreatePage extends React.Component<EventCreatePageProps, EventCreateP
|
||||
// resp.signupForm = (resp.signupForm as any).map(inst => inst.id);
|
||||
resp.tags = data.formData.tags;
|
||||
resp.signupForm = data.formData.signupForm;
|
||||
this.setState({
|
||||
formData: resp,
|
||||
statusMessage: "Event created successfully",
|
||||
});
|
||||
setStatusMessage("Event created successfully");
|
||||
setFormData(resp);
|
||||
} else {
|
||||
const resp = await updateEvent(payload);
|
||||
// TODO: Backend return old data because of Prefetch (used for filtering invisble signupForms from GET)
|
||||
@@ -125,213 +218,39 @@ class EventCreatePage extends React.Component<EventCreatePageProps, EventCreateP
|
||||
// resp.signupForm = (resp.signupForm as any).map(inst => inst.id);
|
||||
resp.tags = data.formData.tags;
|
||||
resp.signupForm = data.formData.signupForm;
|
||||
this.setState({
|
||||
formData: resp,
|
||||
statusMessage: "Event updated successfully",
|
||||
});
|
||||
setStatusMessage("Event updated successfully");
|
||||
setFormData(resp);
|
||||
}
|
||||
} catch (err) {
|
||||
this.setState({
|
||||
error: String(err),
|
||||
});
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
onError = (data) => {
|
||||
console.error("error, data:");
|
||||
console.log(this.state.formData);
|
||||
console.log(data);
|
||||
}
|
||||
const onChange = (data) => setFormData(data.formData);
|
||||
const onFocus = () => setStatusMessage(null);
|
||||
const title = formData?.id
|
||||
? `Edit Event "${formData.title_fi}"`
|
||||
: "Create Event";
|
||||
|
||||
onChange = (data) => {
|
||||
this.setState({
|
||||
formData: data.formData,
|
||||
});
|
||||
}
|
||||
|
||||
onFocus = () => {
|
||||
this.setState({
|
||||
statusMessage: null,
|
||||
});
|
||||
}
|
||||
|
||||
buildSchema = () => {
|
||||
const { tags, signupForm, error } = this.state;
|
||||
|
||||
const formData = this.state.formData as Event;
|
||||
|
||||
const date = new Date();
|
||||
const currentDatetime = date.toISOString();
|
||||
const tomorrowDate = new Date();
|
||||
tomorrowDate.setDate(tomorrowDate.getDate() + 1);
|
||||
const tomorrowDatetime = tomorrowDate.toISOString();
|
||||
|
||||
const schema = {
|
||||
title: formData.id ? formData.title_fi : "New Event",
|
||||
type: "object",
|
||||
required: ["title_fi", "title_en", "tags", "location_fi", "location_en", "start_time", "end_time", "description_fi", "description_en", "content_fi", "content_en"],
|
||||
properties: {
|
||||
tags: {
|
||||
type: "array",
|
||||
title: "Event tags",
|
||||
items: {
|
||||
type: "number",
|
||||
enum: tags.map(t => t.id),
|
||||
enumNames: tags.map(t => t.name_fi),
|
||||
},
|
||||
uniqueItems: true,
|
||||
default: [],
|
||||
},
|
||||
visible: {
|
||||
type: "boolean",
|
||||
title: "Visible",
|
||||
default: true,
|
||||
},
|
||||
start_time: {
|
||||
type: "string",
|
||||
title: "Start time",
|
||||
default: currentDatetime,
|
||||
},
|
||||
end_time: {
|
||||
type: "string",
|
||||
title: "End time",
|
||||
default: tomorrowDatetime,
|
||||
},
|
||||
signupForm: {
|
||||
type: "array",
|
||||
title: "Signup forms",
|
||||
items: {
|
||||
type: "number",
|
||||
// TODO: A bug here, DB must have at least one SignupForm, otherwise cannot submit
|
||||
enum: signupForm.map(form => form.id),
|
||||
enumNames: signupForm.map(form => form.title_fi),
|
||||
},
|
||||
uniqueItems: true,
|
||||
},
|
||||
image: {
|
||||
type: ["string", "null"],
|
||||
format: formData.image ? "uri-reference" : "data-url",
|
||||
title: "Override tag icon with image",
|
||||
default: undefined
|
||||
},
|
||||
finnish_section_divider: {
|
||||
title: "Finnish",
|
||||
type: "string",
|
||||
},
|
||||
title_fi: {
|
||||
type: "string",
|
||||
title: "Title",
|
||||
default: ""
|
||||
},
|
||||
description_fi: {
|
||||
type: "string",
|
||||
title: "Description",
|
||||
default: "",
|
||||
},
|
||||
content_fi: {
|
||||
type: "string",
|
||||
title: "Content",
|
||||
default: "",
|
||||
},
|
||||
location_fi: {
|
||||
type: "string",
|
||||
title: "Location",
|
||||
default: "",
|
||||
},
|
||||
english_section_divider: {
|
||||
title: "English",
|
||||
type: "string",
|
||||
},
|
||||
title_en: {
|
||||
type: "string",
|
||||
title: "Title",
|
||||
default: ""
|
||||
},
|
||||
description_en: {
|
||||
type: "string",
|
||||
title: "Description",
|
||||
default: "",
|
||||
},
|
||||
content_en: {
|
||||
type: "string",
|
||||
title: "Content",
|
||||
default: "",
|
||||
},
|
||||
location_en: {
|
||||
type: "string",
|
||||
title: "Location",
|
||||
default: "",
|
||||
},
|
||||
}
|
||||
};
|
||||
return schema;
|
||||
}
|
||||
|
||||
buildUISchema = () => {
|
||||
const uiSchema = {
|
||||
content_fi: {
|
||||
"ui:widget": "markdownEditor",
|
||||
},
|
||||
content_en: {
|
||||
"ui:widget": "markdownEditor",
|
||||
},
|
||||
start_time: {
|
||||
"ui:widget": "datetime",
|
||||
},
|
||||
end_time: {
|
||||
"ui:widget": "datetime",
|
||||
},
|
||||
image: {
|
||||
"ui:options": {
|
||||
accept: [".jpg", ".jpeg", ".png"]
|
||||
}
|
||||
},
|
||||
finnish_section_divider: {
|
||||
"ui:widget": "section_divider",
|
||||
"ui:options": {
|
||||
label: false
|
||||
},
|
||||
},
|
||||
english_section_divider: {
|
||||
"ui:widget": "section_divider",
|
||||
"ui:options": {
|
||||
label: false
|
||||
},
|
||||
},
|
||||
};
|
||||
return uiSchema;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { error, statusMessage } = this.state;
|
||||
const { formData } = this.state;
|
||||
const schema = this.buildSchema();
|
||||
const uiSchema = this.buildUISchema();
|
||||
|
||||
const title = formData.id
|
||||
? `Edit Event "${formData.title_fi}"`
|
||||
: "Create Event";
|
||||
|
||||
return (
|
||||
<AdminCreateCommon>
|
||||
<Helmet>
|
||||
<link rel="canonical" href="https://sik.ayy.fi/admin/events/create" />
|
||||
</Helmet>
|
||||
<h1>{title}</h1>
|
||||
{statusMessage && <div className="success">{statusMessage}</div>}
|
||||
<Form schema={schema as any}
|
||||
uiSchema={uiSchema}
|
||||
formData={formData}
|
||||
idPrefix="rjsf"
|
||||
widgets={widgets as any}
|
||||
onChange={this.onChange}
|
||||
onSubmit={this.onSubmit}
|
||||
onError={this.onError}
|
||||
onFocus={this.onFocus} />
|
||||
{error && <div className="error">{error}</div>}
|
||||
</AdminCreateCommon>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<link rel="canonical" href="https://sik.ayy.fi/admin/events/create" />
|
||||
</Helmet>
|
||||
<AdminCreateCommon
|
||||
title={title}
|
||||
formData={formData}
|
||||
schema={buildSchema(formData, signupForms, tags)}
|
||||
UISchema={buildUISchema()}
|
||||
onChange={onChange}
|
||||
onFocus={onFocus}
|
||||
onSubmit={onSubmit}
|
||||
statusMessage={statusMessage}
|
||||
error={error}
|
||||
widgets={widgets}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default EventCreatePage;
|
||||
|
||||
+167
-188
@@ -1,230 +1,209 @@
|
||||
import React from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Helmet } from "react-helmet";
|
||||
import Form from "react-jsonschema-form";
|
||||
import { RouteComponentProps } from "react-router-dom";
|
||||
import AdminCreateCommon from "./AdminCreateCommon";
|
||||
import { Tag, getTags } from "@models/Tag";
|
||||
import { Post, createPost, getPost, updatePost } from "@models/Feed";
|
||||
import DatetimeWidget from "@components/Widgets/DatetimeWidget/DatetimeWidget";
|
||||
import SectionDividerWidget from "@components/Widgets/SectionDividerWidget/SectionDividerWidget";
|
||||
import MarkdownEditorWidget from "@components/Widgets/MarkdownEditorWidget";
|
||||
|
||||
const widgets = {
|
||||
datetime: DatetimeWidget,
|
||||
section_divider: SectionDividerWidget,
|
||||
markdownEditor: MarkdownEditorWidget
|
||||
};
|
||||
|
||||
const buildSchema = (formData: Post, tags: Tag[]) => {
|
||||
const date = new Date();
|
||||
const currentDatetime = date.toISOString();
|
||||
|
||||
const schema = {
|
||||
title: formData?.id ? formData.title_fi : "New Post",
|
||||
type: "object",
|
||||
required: ["title_fi", "title_en", "description_fi", "description_en", "content_fi", "content_en", "publish_time"],
|
||||
properties: {
|
||||
tags: {
|
||||
type: "array",
|
||||
title: "Post tags",
|
||||
items: {
|
||||
type: "number",
|
||||
enum: tags.map(t => t.id),
|
||||
enumNames: tags.map(t => t.name_fi),
|
||||
},
|
||||
uniqueItems: true,
|
||||
default: [],
|
||||
},
|
||||
visible: {
|
||||
type: "boolean",
|
||||
title: "Visible",
|
||||
default: true,
|
||||
},
|
||||
publish_time: {
|
||||
type: "string",
|
||||
title: "Publish time",
|
||||
default: currentDatetime,
|
||||
},
|
||||
autohide_enabled: {
|
||||
type: "boolean",
|
||||
title: "Autohide enabled",
|
||||
default: false,
|
||||
},
|
||||
autohide: {
|
||||
type: "string",
|
||||
title: "Autohide time",
|
||||
default: "",
|
||||
},
|
||||
finnish_section_divider: {
|
||||
title: "Finnish",
|
||||
type: "string",
|
||||
},
|
||||
title_fi: {
|
||||
type: "string",
|
||||
title: "Title",
|
||||
default: ""
|
||||
},
|
||||
description_fi: {
|
||||
type: "string",
|
||||
title: "Description",
|
||||
default: "",
|
||||
},
|
||||
content_fi: {
|
||||
type: "string",
|
||||
title: "Content",
|
||||
default: "",
|
||||
},
|
||||
english_section_divider: {
|
||||
title: "English",
|
||||
type: "string",
|
||||
},
|
||||
title_en: {
|
||||
type: "string",
|
||||
title: "Title",
|
||||
default: ""
|
||||
},
|
||||
description_en: {
|
||||
type: "string",
|
||||
title: "Description",
|
||||
default: "",
|
||||
},
|
||||
content_en: {
|
||||
type: "string",
|
||||
title: "Content",
|
||||
default: "",
|
||||
},
|
||||
}
|
||||
};
|
||||
return schema;
|
||||
}
|
||||
|
||||
const buildUISchema = (formData: Post) => {
|
||||
const uiSchema = {
|
||||
content_fi: {
|
||||
"ui:widget": "markdownEditor",
|
||||
},
|
||||
content_en: {
|
||||
"ui:widget": "markdownEditor",
|
||||
},
|
||||
publish_time: {
|
||||
"ui:widget": "datetime",
|
||||
},
|
||||
autohide: {
|
||||
"ui:widget": formData && formData.autohide_enabled ? "datetime" : "hidden",
|
||||
},
|
||||
finnish_section_divider: {
|
||||
"ui:widget": "section_divider",
|
||||
"ui:options": {
|
||||
label: false
|
||||
},
|
||||
},
|
||||
english_section_divider: {
|
||||
"ui:widget": "section_divider",
|
||||
"ui:options": {
|
||||
label: false
|
||||
},
|
||||
},
|
||||
};
|
||||
return uiSchema;
|
||||
}
|
||||
|
||||
interface MatchParams {
|
||||
id?: string;
|
||||
}
|
||||
|
||||
type FeedCreatePageProps = RouteComponentProps<MatchParams>;
|
||||
|
||||
export interface FeedCreatePageState {
|
||||
tags: Tag[];
|
||||
error?: string;
|
||||
statusMessage?: string;
|
||||
formData: Post;
|
||||
}
|
||||
const FeedCreatePage: React.FC<FeedCreatePageProps> = ({ match: { params: { id } } }) => {
|
||||
const [formData, setFormData] = useState<Post>(null);
|
||||
const [tags, setTags] = useState<Tag[]>([]);
|
||||
const [error, setError] = useState<string>(null);
|
||||
const [statusMessage, setStatusMessage] = useState<string>(null);
|
||||
|
||||
class FeedCreatePage extends React.Component<FeedCreatePageProps, FeedCreatePageState> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
tags: [],
|
||||
formData: {} as Post,
|
||||
};
|
||||
useEffect(() => {
|
||||
|
||||
this.fetchTags();
|
||||
getTags()
|
||||
.then(res => setTags(res))
|
||||
.catch(err => setError(err))
|
||||
|
||||
const {id} = props.match.params;
|
||||
if (id !== undefined) {
|
||||
this.fetchInitialFormData(id);
|
||||
const feedId = id && Number(id);
|
||||
if (feedId !== undefined) {
|
||||
getPost(feedId)
|
||||
// getPost(feedId, true)
|
||||
.then(res => setFormData({
|
||||
...res,
|
||||
tags: (res.tags).map(inst => inst.id) as any,
|
||||
}))
|
||||
.catch(err => setError(err))
|
||||
}
|
||||
}
|
||||
|
||||
fetchInitialFormData = async (id) => {
|
||||
try {
|
||||
const data = await getPost(id);
|
||||
// data.tags = data.tag_id;
|
||||
this.setState({
|
||||
formData: data,
|
||||
});
|
||||
} catch (err) {
|
||||
this.setState({
|
||||
error: String(err),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fetchTags = async () => {
|
||||
const getTagsPromise = getTags();
|
||||
try {
|
||||
const tags = await getTagsPromise;
|
||||
this.setState({
|
||||
tags,
|
||||
});
|
||||
return getTagsPromise;
|
||||
} catch (err) {
|
||||
this.setState({
|
||||
error: String(err),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onSubmit = async (data) => {
|
||||
console.log("submitted, data:");
|
||||
console.log(data);
|
||||
}, [id])
|
||||
|
||||
const onSubmit = async (data) => {
|
||||
try {
|
||||
const payload = data.formData;
|
||||
payload.tag_id = payload.tags;
|
||||
payload.autohide = payload.autohide || new Date();
|
||||
|
||||
if (payload.id === undefined) {
|
||||
const resp = await createPost(payload);
|
||||
// resp.tags = resp.tags;
|
||||
this.setState({
|
||||
formData: resp,
|
||||
statusMessage: "Post created successfully",
|
||||
});
|
||||
setStatusMessage("Post created successfully");
|
||||
setFormData(resp);
|
||||
} else {
|
||||
const resp = await updatePost(payload);
|
||||
// resp.tags = resp.tag_id;
|
||||
this.setState({
|
||||
formData: resp,
|
||||
statusMessage: "Post updated successfully.",
|
||||
});
|
||||
setStatusMessage("Post updated successfully");
|
||||
setFormData(resp);
|
||||
}
|
||||
} catch (err) {
|
||||
this.setState({
|
||||
error: String(err),
|
||||
});
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
onError = (data) => {
|
||||
console.error("error, data:");
|
||||
console.log(data);
|
||||
}
|
||||
const onChange = (data) => setFormData(data.formData);
|
||||
const onFocus = () => setStatusMessage(null);
|
||||
|
||||
onChange = (data) => {
|
||||
this.setState({
|
||||
formData: data.formData,
|
||||
});
|
||||
}
|
||||
const title = formData?.id
|
||||
? `Edit Post "${formData.title_fi}"`
|
||||
: "Create Post";
|
||||
|
||||
onFocus = () => {
|
||||
this.setState({
|
||||
statusMessage: null,
|
||||
});
|
||||
}
|
||||
|
||||
buildSchema = () => {
|
||||
const { tags, error, formData } = this.state;
|
||||
|
||||
const date = new Date();
|
||||
const currentDatetime = date.toISOString();
|
||||
|
||||
const schema = {
|
||||
title: formData.id ? formData.title_fi : "New Post",
|
||||
type: "object",
|
||||
required: ["title", "description", "content", "publish_time"],
|
||||
properties: {
|
||||
title: {
|
||||
type: "string",
|
||||
title: "Title",
|
||||
default: ""
|
||||
},
|
||||
tags: {
|
||||
type: "array",
|
||||
title: "Post tags",
|
||||
items: {
|
||||
type: "number",
|
||||
enum: tags.map(t => t.id),
|
||||
enumNames: tags.map(t => t.name_fi),
|
||||
},
|
||||
uniqueItems: true,
|
||||
default: [],
|
||||
},
|
||||
description: {
|
||||
type: "string",
|
||||
title: "Description",
|
||||
default: "",
|
||||
},
|
||||
content: {
|
||||
type: "string",
|
||||
title: "Content",
|
||||
default: "",
|
||||
},
|
||||
publish_time: {
|
||||
type: "string",
|
||||
title: "Publish time",
|
||||
default: currentDatetime,
|
||||
},
|
||||
autohide_enabled: {
|
||||
type: "boolean",
|
||||
title: "Autohide enabled",
|
||||
default: false,
|
||||
},
|
||||
autohide: {
|
||||
type: "string",
|
||||
title: "Autohide time",
|
||||
default: "",
|
||||
},
|
||||
visible: {
|
||||
type: "boolean",
|
||||
title: "Visible",
|
||||
default: true,
|
||||
}
|
||||
}
|
||||
};
|
||||
return schema;
|
||||
}
|
||||
|
||||
buildUISchema = () => {
|
||||
const { formData } = this.state;
|
||||
const { autohide_enabled } = formData;
|
||||
const uiSchema = {
|
||||
content: {
|
||||
"ui:widget": "textarea",
|
||||
},
|
||||
publish_time: {
|
||||
"ui:widget": "datetime",
|
||||
},
|
||||
autohide: {
|
||||
"ui:widget": autohide_enabled ? "datetime" : "hidden",
|
||||
},
|
||||
};
|
||||
return uiSchema;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { error, formData, statusMessage } = this.state;
|
||||
const schema = this.buildSchema();
|
||||
const uiSchema = this.buildUISchema();
|
||||
|
||||
const title = formData.id
|
||||
? `Edit Post "${formData.title_fi}"`
|
||||
: "Create Post";
|
||||
|
||||
return (
|
||||
<AdminCreateCommon>
|
||||
<Helmet>
|
||||
<link rel="canonical" href="https://sik.ayy.fi/admin/feed/create" />
|
||||
</Helmet>
|
||||
<h1>{title}</h1>
|
||||
{statusMessage && <div className="success">{statusMessage}</div>}
|
||||
<Form schema={schema as any}
|
||||
uiSchema={uiSchema}
|
||||
formData={formData}
|
||||
idPrefix="rjsf"
|
||||
widgets={widgets as any}
|
||||
onChange={this.onChange}
|
||||
onSubmit={this.onSubmit}
|
||||
onError={this.onError}
|
||||
onFocus={this.onFocus} />
|
||||
{error && <div className="error">{error}</div>}
|
||||
</AdminCreateCommon>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<link rel="canonical" href="https://sik.ayy.fi/admin/feed/create" />
|
||||
</Helmet>
|
||||
<AdminCreateCommon
|
||||
title={title}
|
||||
formData={formData}
|
||||
schema={buildSchema(formData, tags)}
|
||||
UISchema={buildUISchema(formData)}
|
||||
onChange={onChange}
|
||||
onFocus={onFocus}
|
||||
onSubmit={onSubmit}
|
||||
statusMessage={statusMessage}
|
||||
error={error}
|
||||
widgets={widgets}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default FeedCreatePage;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Helmet } from "react-helmet";
|
||||
import Form from "react-jsonschema-form";
|
||||
import { RouteComponentProps } from "react-router-dom";
|
||||
import AdminCreateCommon from "./AdminCreateCommon";
|
||||
import { JobAd, getJobAd, createJobAd, updateJobAd } from "@models/JobAd";
|
||||
@@ -14,12 +13,12 @@ const widgets = {
|
||||
markdownEditor: MarkdownEditorWidget
|
||||
};
|
||||
|
||||
const buildSchema = (title: string) => {
|
||||
const buildSchema = (formData: JobAd) => {
|
||||
const monthFromNow = new Date();
|
||||
monthFromNow.setDate(new Date().getDate() + 30);
|
||||
|
||||
const schema = {
|
||||
title,
|
||||
title: formData?.id ? formData.title_fi : "New Job Ad",
|
||||
type: "object",
|
||||
required: ["title_fi", "title_en", "description_fi", "description_en", "content_fi", "content_en", "autohide_at", "autohide_enabled", "visible"],
|
||||
properties: {
|
||||
@@ -105,8 +104,6 @@ const buildUISchema = (formData: JobAd) => ({
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
|
||||
interface MatchParams {
|
||||
id?: string;
|
||||
}
|
||||
@@ -114,21 +111,19 @@ interface MatchParams {
|
||||
type JobAdCreatePageProps = RouteComponentProps<MatchParams>;
|
||||
|
||||
const JobAdCreatePage: React.FC<JobAdCreatePageProps> = ({ match: { params: { id } } }) => {
|
||||
|
||||
const [formData, setFormData] = useState<JobAd>(null);
|
||||
const [error, setError] = useState<string>(null);
|
||||
const [statusMessage, setStatusMessage] = useState<string>(null);
|
||||
useEffect(() => {
|
||||
const jobId = id && Number(id);
|
||||
if (jobId !== undefined) {
|
||||
getJobAd(jobId, true)
|
||||
.then(res => setFormData(res))
|
||||
.catch(err => setError(err))
|
||||
}
|
||||
}, [id])
|
||||
|
||||
|
||||
|
||||
const [error, setError] = useState<string>(null);
|
||||
const [statusMessage, setStatusMessage] = useState<string>(null);
|
||||
|
||||
const onSubmit = async (data) => {
|
||||
try {
|
||||
const payload = data.formData;
|
||||
@@ -146,10 +141,6 @@ const JobAdCreatePage: React.FC<JobAdCreatePageProps> = ({ match: { params: { id
|
||||
}
|
||||
}
|
||||
|
||||
const onError = (data) => {
|
||||
console.error("error, data:");
|
||||
console.log(data);
|
||||
}
|
||||
const onChange = (data) => setFormData(data.formData);
|
||||
const onFocus = () => setStatusMessage(null);
|
||||
|
||||
@@ -158,24 +149,23 @@ const JobAdCreatePage: React.FC<JobAdCreatePageProps> = ({ match: { params: { id
|
||||
: "Create Ad";
|
||||
|
||||
return (
|
||||
<AdminCreateCommon>
|
||||
<>
|
||||
<Helmet>
|
||||
<link rel="canonical" href="https://sik.ayy.fi/admin/jobads/create" />
|
||||
</Helmet>
|
||||
<h1>{title}</h1>
|
||||
{statusMessage && <div className="success">{statusMessage}</div>}
|
||||
<Form
|
||||
schema={buildSchema(formData?.id ? formData.title_fi : "New Post") as any}
|
||||
uiSchema={buildUISchema(formData)}
|
||||
<AdminCreateCommon
|
||||
title={title}
|
||||
formData={formData}
|
||||
idPrefix="rjsf"
|
||||
widgets={widgets as any}
|
||||
schema={buildSchema(formData)}
|
||||
UISchema={buildUISchema(formData)}
|
||||
onChange={onChange}
|
||||
onFocus={onFocus}
|
||||
onSubmit={onSubmit}
|
||||
onError={onError}
|
||||
onFocus={onFocus} />
|
||||
{error && <div className="error">{error}</div>}
|
||||
</AdminCreateCommon>
|
||||
statusMessage={statusMessage}
|
||||
error={error}
|
||||
widgets={widgets}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Helmet } from "react-helmet";
|
||||
import { Link } from "react-router-dom";
|
||||
import Form from "react-jsonschema-form";
|
||||
import { RouteComponentProps } from "react-router-dom";
|
||||
import AdminCreateCommon from "./AdminCreateCommon";
|
||||
import { SignupForm, createForm, getForm, updateForm } from "@models/SignupForm";
|
||||
import DatetimeWidget from "@components/Widgets/DatetimeWidget/DatetimeWidget";
|
||||
@@ -9,62 +8,119 @@ import SignupQuestionsWidget from "@components/Widgets/SignupQuestionsWidget";
|
||||
import MarkdownEditorWidget from "@components/Widgets/MarkdownEditorWidget";
|
||||
import { buildValidationSchema } from "@views/SignUpPage/FormUtils";
|
||||
|
||||
const widgets = {
|
||||
datetime: DatetimeWidget,
|
||||
signup: SignupQuestionsWidget,
|
||||
markdownEditor: MarkdownEditorWidget
|
||||
};
|
||||
const DEFAULT_EMAIL =
|
||||
`Moikka,
|
||||
|
||||
Ilmottautuminen saapui perille.`
|
||||
;
|
||||
export interface SignupCreatePageProps {
|
||||
history: {
|
||||
push: (to: string) => void;
|
||||
|
||||
const widgets = {
|
||||
datetime: DatetimeWidget,
|
||||
signup: SignupQuestionsWidget,
|
||||
markdownEditor: MarkdownEditorWidget
|
||||
};
|
||||
|
||||
const buildSchema = (formData: SignupForm) => {
|
||||
const date = new Date();
|
||||
const currentDatetime = date.toISOString();
|
||||
const tomorrowDate = new Date();
|
||||
tomorrowDate.setDate(tomorrowDate.getDate() + 1);
|
||||
const tomorrowDatetime = tomorrowDate.toISOString();
|
||||
|
||||
const schema = {
|
||||
title: formData?.id ? formData.title_fi : "New Sign-up form",
|
||||
type: "object",
|
||||
required: ["title_fi", "title_en", "start_time", "end_time", "questions"],
|
||||
properties: {
|
||||
title_fi: {
|
||||
type: "string",
|
||||
title: "Title (FI)",
|
||||
default: "",
|
||||
},
|
||||
title_en: {
|
||||
type: "string",
|
||||
title: "Title (EN)",
|
||||
default: "",
|
||||
},
|
||||
visible: {
|
||||
type: "boolean",
|
||||
title: "Visible",
|
||||
default: false,
|
||||
},
|
||||
quota: {
|
||||
type: "integer",
|
||||
title: "Quota",
|
||||
minimum: 0,
|
||||
default: 0,
|
||||
},
|
||||
start_time: {
|
||||
type: "string",
|
||||
title: "Start time",
|
||||
default: currentDatetime,
|
||||
},
|
||||
end_time: {
|
||||
type: "string",
|
||||
title: "End time",
|
||||
default: tomorrowDatetime,
|
||||
},
|
||||
email_content: {
|
||||
type: "string",
|
||||
title: "Email on signup",
|
||||
default: DEFAULT_EMAIL
|
||||
},
|
||||
questions: {
|
||||
type: "string",
|
||||
title: "Questions",
|
||||
default: "[]",
|
||||
},
|
||||
},
|
||||
};
|
||||
match: {
|
||||
params: {
|
||||
id?: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
export interface SignupCreatePageState {
|
||||
error?: string;
|
||||
statusMessage?: string;
|
||||
formData: SignupForm;
|
||||
return schema;
|
||||
}
|
||||
|
||||
class SignupCreatePage extends React.Component<SignupCreatePageProps, SignupCreatePageState> {
|
||||
constructor(props: SignupCreatePageProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
formData: {} as SignupForm,
|
||||
};
|
||||
const buildUISchema = () => {
|
||||
const uiSchema = {
|
||||
email_content: {
|
||||
"ui:widget": "markdownEditor",
|
||||
},
|
||||
start_time: {
|
||||
"ui:widget": "datetime",
|
||||
},
|
||||
end_time: {
|
||||
"ui:widget": "datetime",
|
||||
},
|
||||
questions: {
|
||||
"ui:widget": "signup",
|
||||
},
|
||||
};
|
||||
return uiSchema;
|
||||
}
|
||||
|
||||
const {id} = props.match.params;
|
||||
if (id !== undefined) {
|
||||
this.fetchInitialFormData(id);
|
||||
interface MatchParams {
|
||||
id?: string;
|
||||
}
|
||||
|
||||
type SignupCreatePageProps = RouteComponentProps<MatchParams>;
|
||||
|
||||
const SignupCreatePage: React.FC<SignupCreatePageProps> = ({ match: { params: { id } } }) => {
|
||||
const [formData, setFormData] = useState<SignupForm>(null);
|
||||
const [error, setError] = useState<string>(null);
|
||||
const [statusMessage, setStatusMessage] = useState<string>(null);
|
||||
useEffect(() => {
|
||||
const suId = id && Number(id);
|
||||
if (suId !== undefined) {
|
||||
getForm(suId, true)
|
||||
.then(res => {
|
||||
setFormData({
|
||||
...res,
|
||||
questions: JSON.stringify(res.questions) as any
|
||||
});
|
||||
})
|
||||
.catch(err => setError(err))
|
||||
}
|
||||
}
|
||||
}, [id])
|
||||
|
||||
fetchInitialFormData = async (id: number) => {
|
||||
try {
|
||||
const data = await getForm(id, true);
|
||||
this.setState({
|
||||
formData: {
|
||||
...data,
|
||||
questions: JSON.stringify(data.questions) as any
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
this.setState({
|
||||
error: String(err),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onSubmit = async (data: any) => {
|
||||
const onSubmit = async (data: any) => {
|
||||
try {
|
||||
const questions = JSON.parse(data.formData.questions);
|
||||
const payload: SignupForm = {
|
||||
@@ -75,158 +131,53 @@ class SignupCreatePage extends React.Component<SignupCreatePageProps, SignupCrea
|
||||
|
||||
if (payload.id === undefined) {
|
||||
const resp = await createForm(payload);
|
||||
this.setState({
|
||||
formData: {
|
||||
...resp,
|
||||
questions: JSON.stringify(resp.questions) as any
|
||||
},
|
||||
statusMessage: "Sign-up created successfully",
|
||||
setStatusMessage("Sign-up created successfully");
|
||||
setFormData({
|
||||
...resp,
|
||||
questions: JSON.stringify(resp.questions) as any
|
||||
});
|
||||
} else {
|
||||
const resp = await updateForm(payload);
|
||||
this.setState({
|
||||
formData: {
|
||||
...resp,
|
||||
questions: JSON.stringify(resp.questions) as any
|
||||
},
|
||||
statusMessage: "Sign-up updated successfully.",
|
||||
setStatusMessage("Sign-up updated successfully");
|
||||
setFormData({
|
||||
...resp,
|
||||
questions: JSON.stringify(resp.questions) as any
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
this.setState({
|
||||
error: error,
|
||||
statusMessage: error.message
|
||||
});
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
onError = (data) => {
|
||||
console.error("error, data:");
|
||||
console.log(data);
|
||||
}
|
||||
const onChange = (data) => setFormData(data.formData);
|
||||
const onFocus = () => setStatusMessage(null);
|
||||
|
||||
onChange = (data) => {
|
||||
this.setState({
|
||||
formData: data.formData,
|
||||
});
|
||||
}
|
||||
const title = formData?.id
|
||||
? `Edit Sign-up Form "${formData.title_fi}"`
|
||||
: "Create Sign-up form";
|
||||
|
||||
onFocus = () => {
|
||||
this.setState({
|
||||
statusMessage: null,
|
||||
});
|
||||
}
|
||||
|
||||
buildSchema = () => {
|
||||
const { error, formData } = this.state;
|
||||
|
||||
const date = new Date();
|
||||
const currentDatetime = date.toISOString();
|
||||
const tomorrowDate = new Date();
|
||||
tomorrowDate.setDate(tomorrowDate.getDate() + 1);
|
||||
const tomorrowDatetime = tomorrowDate.toISOString();
|
||||
|
||||
const schema = {
|
||||
title: formData.id ? formData.title_fi : "New Sign-up form",
|
||||
type: "object",
|
||||
required: ["title_fi", "title_en", "start_time", "end_time", "questions"],
|
||||
properties: {
|
||||
title_fi: {
|
||||
type: "string",
|
||||
title: "Title (FI)",
|
||||
default: "",
|
||||
},
|
||||
title_en: {
|
||||
type: "string",
|
||||
title: "Title (EN)",
|
||||
default: "",
|
||||
},
|
||||
visible: {
|
||||
type: "boolean",
|
||||
title: "Visible",
|
||||
default: false,
|
||||
},
|
||||
quota: {
|
||||
type: "integer",
|
||||
title: "Quota",
|
||||
minimum: 0,
|
||||
default: 0,
|
||||
},
|
||||
start_time: {
|
||||
type: "string",
|
||||
title: "Start time",
|
||||
default: currentDatetime,
|
||||
},
|
||||
end_time: {
|
||||
type: "string",
|
||||
title: "End time",
|
||||
default: tomorrowDatetime,
|
||||
},
|
||||
email_content: {
|
||||
type: "string",
|
||||
title: "Email on signup",
|
||||
default: DEFAULT_EMAIL
|
||||
},
|
||||
questions: {
|
||||
type: "string",
|
||||
title: "Questions",
|
||||
default: "[]",
|
||||
},
|
||||
},
|
||||
};
|
||||
return schema;
|
||||
}
|
||||
|
||||
buildUISchema = () => {
|
||||
const uiSchema = {
|
||||
email_content: {
|
||||
"ui:widget": "markdownEditor",
|
||||
},
|
||||
start_time: {
|
||||
"ui:widget": "datetime",
|
||||
},
|
||||
end_time: {
|
||||
"ui:widget": "datetime",
|
||||
},
|
||||
questions: {
|
||||
"ui:widget": "signup",
|
||||
},
|
||||
};
|
||||
return uiSchema;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { error, formData, statusMessage } = this.state;
|
||||
const schema = this.buildSchema();
|
||||
const uiSchema = this.buildUISchema();
|
||||
|
||||
const title = formData.id
|
||||
? `Edit Sign-up Form "${formData.title_fi}"`
|
||||
: "Create Sign-up form";
|
||||
|
||||
return (
|
||||
<AdminCreateCommon>
|
||||
<Helmet>
|
||||
<link rel="canonical" href="https://sik.ayy.fi/admin/signups/create" />
|
||||
</Helmet>
|
||||
<h1>{title}</h1>
|
||||
{statusMessage && <div className="success">{statusMessage}</div>}
|
||||
{formData.id && <p>
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<link rel="canonical" href="https://sik.ayy.fi/admin/signups/create" />
|
||||
</Helmet>
|
||||
<AdminCreateCommon
|
||||
title={title}
|
||||
formData={formData}
|
||||
schema={buildSchema(formData)}
|
||||
UISchema={buildUISchema()}
|
||||
onChange={onChange}
|
||||
onFocus={onFocus}
|
||||
onSubmit={onSubmit}
|
||||
statusMessage={statusMessage}
|
||||
error={error}
|
||||
widgets={widgets}
|
||||
/>
|
||||
{/* {formData.id && <p>
|
||||
Check out the signup form here: <Link to={`/signup/${formData.id}`}>{formData.title_fi}</Link>
|
||||
</p>}
|
||||
<Form schema={schema as any}
|
||||
uiSchema={uiSchema}
|
||||
formData={formData}
|
||||
idPrefix="rjsf"
|
||||
widgets={widgets as any}
|
||||
onChange={this.onChange}
|
||||
onSubmit={this.onSubmit}
|
||||
onError={this.onError}
|
||||
onFocus={this.onFocus} />
|
||||
{error && <div className="error">{error}</div>}
|
||||
</AdminCreateCommon>
|
||||
);
|
||||
}
|
||||
</p>} */}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default SignupCreatePage;
|
||||
|
||||
Reference in New Issue
Block a user