Merge branch 'feature/signup-improvements' into 'master'
Simple email & list views for Signups See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!15
This commit is contained in:
+18
-4
@@ -8,7 +8,7 @@ export interface Signup {
|
||||
answer: string;
|
||||
}
|
||||
|
||||
export async function getSignup(id: number): Promise<Signup> {
|
||||
export const getSignup = async (id: number): Promise<Signup> => {
|
||||
try {
|
||||
const resp = await axios.get(`${url}${id}`, {
|
||||
headers: {
|
||||
@@ -22,7 +22,7 @@ export async function getSignup(id: number): Promise<Signup> {
|
||||
}
|
||||
}
|
||||
|
||||
export async function createSignup(data: Signup): Promise<Signup> {
|
||||
export const createSignup = async (data: Signup): Promise<Signup> => {
|
||||
try {
|
||||
const resp = await axios.post(url, data);
|
||||
return resp.data;
|
||||
@@ -32,7 +32,7 @@ export async function createSignup(data: Signup): Promise<Signup> {
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateSignup(data: Signup, uuid: string): Promise<Signup> {
|
||||
export const updateSignup = async (data: Signup, uuid: string): Promise<Signup> => {
|
||||
try {
|
||||
const { id } = data;
|
||||
if (!id) throw new Error("SignupId required!");
|
||||
@@ -46,7 +46,7 @@ export async function updateSignup(data: Signup, uuid: string): Promise<Signup>
|
||||
}
|
||||
}
|
||||
|
||||
export async function getSignupUUID(id: number, uuid: string): Promise<Signup> {
|
||||
export const getSignupUUID = async (id: number, uuid: string): Promise<Signup> => {
|
||||
try {
|
||||
const resp = await axios.get(`${url}${id}/edit/`, {
|
||||
params: {
|
||||
@@ -59,3 +59,17 @@ export async function getSignupUUID(id: number, uuid: string): Promise<Signup> {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
export const deleteSignup = async (id: number): Promise<Signup> => {
|
||||
try {
|
||||
const resp = await axios.delete(`${url}${id}`, {
|
||||
headers: {
|
||||
"Authorization": getAuthHeader()
|
||||
},
|
||||
});
|
||||
return resp.data;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import axios from "axios";
|
||||
import { getAuthHeader } from "@utils/auth";
|
||||
const url = `${process.env.API_URL}/signupForm/`;
|
||||
import { Question } from "@components/Widgets/SignupQuestionsWidget";
|
||||
import { Signup } from "./Signup";
|
||||
|
||||
export interface SignupForm {
|
||||
id?: number;
|
||||
@@ -77,3 +78,31 @@ export async function updateForm(data): Promise<SignupForm> {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
export const signupFormSendEmail = async (data, id): Promise<any> => {
|
||||
try {
|
||||
const resp = await axios.post(`${process.env.API_URL}/signupForm/${id}/sendemail/`, data, {
|
||||
headers: {
|
||||
"Authorization": getAuthHeader(),
|
||||
},
|
||||
});
|
||||
return resp.data;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
export const getSignups = async (id): Promise<Signup[]> => {
|
||||
try {
|
||||
const resp = await axios.get(`${process.env.API_URL}/signupForm/${id}/signups/`, {
|
||||
headers: {
|
||||
"Authorization": getAuthHeader(),
|
||||
},
|
||||
});
|
||||
return resp.data;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ const renderData = (signupForms: SignupForm[]) => {
|
||||
<th>Title</th>
|
||||
<th>Start time</th>
|
||||
<th>End time</th>
|
||||
<th>Sign-ups</th>
|
||||
<th>Send email</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -28,6 +30,8 @@ const renderData = (signupForms: SignupForm[]) => {
|
||||
<td><Anchor to={`${URL}/${signupForm.id}`}>{signupForm.title_fi}</Anchor></td>
|
||||
<td>{formatRelative(new Date(signupForm.start_time), new Date())}</td>
|
||||
<td>{formatRelative(new Date(signupForm.end_time), new Date())}</td>
|
||||
<td><Anchor to={`${URL}/${signupForm.id}/list`}>View</Anchor></td>
|
||||
<td><Anchor to={`${URL}/${signupForm.id}/email`}>Send</Anchor></td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Helmet } from "react-helmet";
|
||||
import { RouteComponentProps } from "react-router-dom";
|
||||
import AdminCreateCommon from "@views/admin/AdminCreateCommon";
|
||||
import MarkdownEditorWidget from "@components/Widgets/MarkdownEditorWidget";
|
||||
import { SignupForm, getForm, signupFormSendEmail } from "@models/SignupForm";
|
||||
|
||||
const widgets = {
|
||||
markdownEditor: MarkdownEditorWidget
|
||||
};
|
||||
|
||||
const buildSchema = (title: string) => {
|
||||
return {
|
||||
title,
|
||||
type: "object",
|
||||
required: ["subject", "content", "mode"],
|
||||
properties: {
|
||||
subject: {
|
||||
type: "string",
|
||||
title: "Title",
|
||||
default: ""
|
||||
},
|
||||
content: {
|
||||
type: "string",
|
||||
title: "Content",
|
||||
default: "",
|
||||
},
|
||||
mode: {
|
||||
type: "string",
|
||||
title: "Send to",
|
||||
enum : [
|
||||
"all",
|
||||
"actual",
|
||||
"reserved"
|
||||
],
|
||||
default: "all",
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const buildUISchema = () => ({
|
||||
content: {
|
||||
"ui:widget": "markdownEditor",
|
||||
},
|
||||
});
|
||||
|
||||
interface MatchParams {
|
||||
id?: string;
|
||||
}
|
||||
|
||||
type SignupEmailPageProps = RouteComponentProps<MatchParams>;
|
||||
|
||||
|
||||
const SignupEmailPage: React.FC<SignupEmailPageProps> = ({ match: { params: { id } } }) => {
|
||||
const [signupForm, setSignupForm] = useState<SignupForm>(null);
|
||||
useEffect(() => {
|
||||
const formId = Number(id);
|
||||
if (formId !== undefined) {
|
||||
getForm(formId, true)
|
||||
.then(res => setSignupForm(res))
|
||||
}
|
||||
}, [id])
|
||||
|
||||
|
||||
|
||||
const [error, setError] = useState<string>(null);
|
||||
const [statusMessage, setStatusMessage] = useState<string>(null);
|
||||
|
||||
const onSubmit = async (data) => {
|
||||
try {
|
||||
const payload = data.formData;
|
||||
await signupFormSendEmail(payload, id);
|
||||
setStatusMessage("Email sent successfully");
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
// const onChange = (data) => setFormData(data.formData);
|
||||
const onFocus = () => setStatusMessage(null);
|
||||
|
||||
const title = signupForm ? signupForm.title_fi : "Loading..."
|
||||
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<link rel="canonical" href="https://sik.ayy.fi/admin/jobads/create" />
|
||||
</Helmet>
|
||||
<AdminCreateCommon
|
||||
title={title}
|
||||
// formData={formData}
|
||||
schema={buildSchema(title)}
|
||||
UISchema={buildUISchema()}
|
||||
// onChange={onChange}
|
||||
onFocus={onFocus}
|
||||
onSubmit={onSubmit}
|
||||
statusMessage={statusMessage}
|
||||
error={error}
|
||||
widgets={widgets}
|
||||
/>
|
||||
</>
|
||||
)};
|
||||
|
||||
export default SignupEmailPage;
|
||||
@@ -0,0 +1,79 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Helmet } from "react-helmet";
|
||||
import { RouteComponentProps } from "react-router-dom";
|
||||
import AdminListCommon from "@views/admin/AdminListCommon";
|
||||
import { SignupForm, getForm, getSignups } from "@models/SignupForm";
|
||||
import { Signup, deleteSignup } from "@models/Signup";
|
||||
|
||||
interface MatchParams {
|
||||
id?: string;
|
||||
}
|
||||
|
||||
type SignupEmailPageProps = RouteComponentProps<MatchParams>;
|
||||
|
||||
|
||||
const SignupEmailPage: React.FC<SignupEmailPageProps> = ({ match: { params: { id } } }) => {
|
||||
const [signupForm, setSignupForm] = useState<SignupForm>(null);
|
||||
const [signups, setSignups] = useState<Signup[]>([]);
|
||||
useEffect(() => {
|
||||
const formId = Number(id);
|
||||
getForm(formId, true)
|
||||
.then(res => setSignupForm(res))
|
||||
|
||||
getSignups(formId).then(res => setSignups(res))
|
||||
|
||||
}, [id]);
|
||||
|
||||
const questions = signupForm ? signupForm.questions.map(q => ({
|
||||
title: q.name,
|
||||
id: q.id
|
||||
})) : [];
|
||||
|
||||
const title = signupForm ? signupForm.title_fi : "Loading...";
|
||||
|
||||
const confirmDelete = async (signup: Signup, question: any) => {
|
||||
if(confirm(`Delete: ${signup.id}: ${signup.answer[question.id]}; Are you sure?`) === true) {
|
||||
try {
|
||||
await deleteSignup(signup.id);
|
||||
setSignups(signups.filter(s => s.id !== signup.id))
|
||||
} catch (err) {
|
||||
alert("Delete failed!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<AdminListCommon>
|
||||
<Helmet>
|
||||
<link rel="canonical" href="https://sik.ayy.fi/admin/jobads/create" />
|
||||
</Helmet>
|
||||
<h1>{title}: Sign-ups</h1>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
{questions.map(q => (
|
||||
<th key={q.id}>{q.title}</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{signups.map(s => (
|
||||
<tr key={s.id}>
|
||||
{questions.map(q => (
|
||||
<td key={`${s.id} - ${q.id}`}>
|
||||
{s.answer[q.id]}
|
||||
</td>
|
||||
))}
|
||||
<td>
|
||||
<button onClick={() => confirmDelete(s, questions[0])}>
|
||||
Delete
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</AdminListCommon>
|
||||
)};
|
||||
|
||||
export default SignupEmailPage;
|
||||
@@ -18,6 +18,8 @@ import EventCreatePage from "./pages/admin/EventCreatePage";
|
||||
import FeedCreatePage from "./pages/admin/FeedCreatePage";
|
||||
import ContactsPage from "./pages/ContactsPage";
|
||||
import SignupCreatePage from "./pages/admin/SignupCreatePage";
|
||||
import SignupEmailPage from "./pages/admin/SignupEmailPage";
|
||||
import SignupListPage from "./pages/admin/SignupListPage";
|
||||
import SignUpPage from "./pages/SignUpPage";
|
||||
import ActualPage from "./pages/ActualPage";
|
||||
import FreshmenPage from "./pages/FreshmenPage";
|
||||
@@ -70,6 +72,8 @@ const adminRoutes = [
|
||||
{ path: "/admin/signups", page: AdminSignupPage },
|
||||
{ path: "/admin/signups/create", page: SignupCreatePage },
|
||||
{ path: "/admin/signups/:id", page: SignupCreatePage },
|
||||
{ path: "/admin/signups/:id/list", page: SignupListPage },
|
||||
{ path: "/admin/signups/:id/email", page: SignupEmailPage },
|
||||
{ path: "/admin/jobads", page: AdminJobAdPage },
|
||||
{ path: "/admin/jobads/create", page: JobAdCreatePage },
|
||||
{ path: "/admin/jobads/:id", page: JobAdCreatePage },
|
||||
|
||||
@@ -16,9 +16,6 @@ const questionToUISchemaProp = (question: Question) => {
|
||||
"ui:widget": "radio",
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new Error(`No mapping to UI schema prop for question type ${question.type}`);
|
||||
}
|
||||
return {
|
||||
[question.id]: obj,
|
||||
};
|
||||
|
||||
@@ -51,7 +51,7 @@ const StyledSection = styled(TextSection)`
|
||||
}
|
||||
|
||||
.reserved {
|
||||
color: color(blue1);
|
||||
color: ${colors.blue1};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ type AdminCreateCommonProps = {
|
||||
UISchema: {
|
||||
[name: string]: any;
|
||||
};
|
||||
onChange: (e: IChangeEvent<FormTypes>, es?: ErrorSchema) => any;
|
||||
onChange?: (e: IChangeEvent<FormTypes>, es?: ErrorSchema) => any;
|
||||
onFocus: (id: string, value: string | number | boolean) => void;
|
||||
onSubmit: (e: ISubmitEvent<FormTypes>) => any;
|
||||
statusMessage: string;
|
||||
|
||||
Reference in New Issue
Block a user