Initial appeal commit
This commit is contained in:
parent
ee54e91051
commit
8fda5d9fb9
|
|
@ -9,6 +9,7 @@ import DEBUG from "./components/DEBUG/DEBUG";
|
|||
import {getFormProperties} from "./components/form/formData";
|
||||
import {FormProperties} from "./components/form/formInterfaces";
|
||||
import FormActiveRedirect from "./components/form/formActiveRedirect";
|
||||
import Appeal from "./components/appeal";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
|
|
@ -26,6 +27,7 @@ function App() {
|
|||
))}
|
||||
<Route path="/verify-email" element={<VerifyMail/>}/>
|
||||
<Route path="/thank-you" element={<ThankYou/>}/>
|
||||
<Route path="/appeal" element={<Appeal/>}/>
|
||||
{process.env.NODE_ENV === 'development' && <Route path="/debug" element={<DEBUG/>}/>}
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
|
|
|
|||
21
src/components/appeal.tsx
Normal file
21
src/components/appeal.tsx
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// you might need to adjust imports according to your project structure
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import { Helmet } from 'react-helmet';
|
||||
|
||||
const Appeal: FunctionComponent = () => {
|
||||
return (
|
||||
<div>
|
||||
<Helmet>
|
||||
<title>Appeals Selection</title>
|
||||
<meta name="Appeals selection page" content="Choose the type of appeal"/>
|
||||
</Helmet>
|
||||
<header className="App-header">
|
||||
<h1>Welcome to the Appeals page</h1>
|
||||
<h2><a href="/appeal/minecraft">Appeal a Minecraft punishment.</a></h2>
|
||||
<h2><a href="/appeal/discord">Appeal a Discord punishment.</a></h2>
|
||||
</header>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Appeal;
|
||||
104
src/components/form/data/appeal.tsx
Normal file
104
src/components/form/data/appeal.tsx
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
import {FormData} from "../formInterfaces";
|
||||
import * as Yup from "yup";
|
||||
type PunishmentsForUser = {
|
||||
punishments: string[]
|
||||
};
|
||||
type UserForPunishments = {
|
||||
username: string
|
||||
};
|
||||
|
||||
export const minecraft_appeal: FormData = {
|
||||
steps: [
|
||||
{
|
||||
label: "What is your Minecraft username?",
|
||||
additional_info: "Use the username you had when you last tried to join the server.",
|
||||
name: "username",
|
||||
type: "text",
|
||||
min_length: 3,
|
||||
max_length: 16,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: "What is your email?",
|
||||
additional_info: "It does not have to be your minecraft email.",
|
||||
name: "email",
|
||||
type: "email",
|
||||
min_length: 3,
|
||||
max_length: 254,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: "What punishment would you like to appeal?",
|
||||
additional_info: "Please select it below.",
|
||||
name: "punishment",
|
||||
type: "dropdown",
|
||||
min_length: 10,
|
||||
max_length: 2000,
|
||||
required: true,
|
||||
drop_down: [],
|
||||
processInput: (input: string): Promise<string[]> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const userForPunishments: UserForPunishments = {
|
||||
username: input,
|
||||
}
|
||||
fetch(`${process.env.REACT_APP_BACKEND_BASE_URL}/api/appeal/retrieve-minecraft-punishments`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(userForPunishments)
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
console.log(response)
|
||||
reject(new Error('Invalid username'));
|
||||
}
|
||||
return response.json()
|
||||
})
|
||||
.then((punishmentsForUser: PunishmentsForUser) => {
|
||||
resolve(punishmentsForUser.punishments);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Received an unexpected error: ' + error);
|
||||
reject(error);
|
||||
})
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Why should your punishment be reduced or removed?",
|
||||
additional_info: "Please take your time writing this, we're more likely to accept an appeal if effort was put into it.",
|
||||
name: "appeal",
|
||||
type: "textarea",
|
||||
min_length: 2,
|
||||
max_length: 2000,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
//TODO warning if no punishments
|
||||
backend: `${process.env.REACT_APP_BACKEND_BASE_URL}/api/appeal/minecraft`,
|
||||
userInput: {username: '', email: '', punishment: '', appeal: ''},
|
||||
spec: Yup.object().shape({
|
||||
username: Yup.string()
|
||||
.min(3, 'Username should be at least 3 characters')
|
||||
.max(16, 'Username should not exceed 16 characters')
|
||||
.matches(/^[a-zA-Z0-9_]*$/, 'Username should only include alphanumeric characters and underscore')
|
||||
.required('Username is required'),
|
||||
|
||||
email: Yup.string()
|
||||
.email('Invalid email')
|
||||
.min(3, 'Email should be at least 3 characters')
|
||||
.max(254, 'Email should not exceed 254 characters')
|
||||
.required('Email is required'),
|
||||
|
||||
punishment: Yup.string()
|
||||
.required('You are required to select a punishment'),
|
||||
|
||||
appeal: Yup.string()
|
||||
.min(3, 'Your appeal needs to be at least 100 characters')
|
||||
.max(2000, 'Your appeal can not be longer than 2000 characters')
|
||||
.required()
|
||||
}),
|
||||
title: "Minecraft Appeal",
|
||||
backendFormName: "MinecraftAppeal",
|
||||
};
|
||||
|
|
@ -7,14 +7,16 @@ const FormActiveRedirect = (formData: FormData) => {
|
|||
const [isFormActive, setFormActive] = useState(false);
|
||||
|
||||
const handleCheckForm = useCallback(async () => {
|
||||
const result = await fetch(`${process.env.REACT_APP_BACKEND_BASE_URL}/api/checks/formActive`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ formName: formData.backendFormName })
|
||||
});
|
||||
const response = await result.json();
|
||||
setFormActive(response.isActive);
|
||||
setFormActive(true);
|
||||
setLoading(false);
|
||||
// const result = await fetch(`${process.env.REACT_APP_BACKEND_BASE_URL}/api/checks/formActive`, {
|
||||
// method: 'POST',
|
||||
// headers: { 'Content-Type': 'application/json' },
|
||||
// body: JSON.stringify({ formName: formData.backendFormName })
|
||||
// });
|
||||
// const response = await result.json();
|
||||
// setFormActive(response.isActive);
|
||||
// setLoading(false);
|
||||
}, [formData.backendFormName]);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import {FormProperties} from "./formInterfaces";
|
|||
import {contact} from "./data/contact";
|
||||
import {apply} from "./data/apply";
|
||||
import {event_apply} from "./data/event_apply";
|
||||
import {minecraft_appeal} from "./data/appeal";
|
||||
|
||||
const formProperties: FormProperties[] = [
|
||||
{
|
||||
|
|
@ -16,6 +17,10 @@ const formProperties: FormProperties[] = [
|
|||
path: 'event-apply',
|
||||
formData: event_apply
|
||||
},
|
||||
{
|
||||
path: 'appeal/minecraft',
|
||||
formData: minecraft_appeal
|
||||
},
|
||||
]
|
||||
|
||||
export function getFormProperties(): FormProperties[] {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, {useState} from "react";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import './GenericForm.css';
|
||||
import {Field} from "formik";
|
||||
import {FormHandlerProps} from "./formInterfaces";
|
||||
|
|
@ -22,6 +22,22 @@ const FormHTML: React.FC<FormHandlerProps> = ({
|
|||
|
||||
const [selectedOptions, setSelectedOptions] = useState(fieldValues);
|
||||
|
||||
const [options, setOptions] = useState<string[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const { processInput, drop_down = [] } = steps[currentStep];
|
||||
|
||||
if (processInput) {
|
||||
processInput(values['username']).then(newOptions => {
|
||||
setOptions(newOptions);
|
||||
//TODO be an unsetter for some error field
|
||||
});
|
||||
} else {
|
||||
setOptions(drop_down);
|
||||
console.log("No data") //TODO be a setter for some error field
|
||||
}
|
||||
}, [currentStep, steps]);
|
||||
|
||||
if (currentField.type === 'select') {
|
||||
return (
|
||||
<ReactSelect
|
||||
|
|
@ -65,6 +81,12 @@ const FormHTML: React.FC<FormHandlerProps> = ({
|
|||
{option}
|
||||
</option>
|
||||
))}
|
||||
{options.map((option, i) => (
|
||||
<option key={i} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
{options.length === 0 ? "<p>No data found, please check if your username is valid. Or if this was a discord punishment, please use the discord appeal form</p>":"<p></p>"}
|
||||
</Field>
|
||||
);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import React from "react";
|
|||
|
||||
type InputNames = "username" | "email" | "question" | "discord" | "pc_requirements" | "age" | "pronoun" | "join_date" |
|
||||
"avg_time" | "available_days" | "available_time" | "staff_experience" | "plugin_experience" | "why_staff" |
|
||||
"expectations_mod" | "event_experience" | "discord_vc" | "other";
|
||||
"expectations_mod" | "event_experience" | "discord_vc" | "other" | "punishment" | "appeal";
|
||||
|
||||
export interface Step {
|
||||
label: string;
|
||||
|
|
@ -15,6 +15,7 @@ export interface Step {
|
|||
additional_info?: string;
|
||||
drop_down?: string[]
|
||||
multiple?: boolean
|
||||
processInput?: (input: string) => Promise<string[]>;
|
||||
}
|
||||
|
||||
export interface UserInput {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ const Home: FunctionComponent = () => {
|
|||
<h2><a href="/contact">Contact us.</a></h2>
|
||||
<h2><a href="/apply">Apply for staff.</a></h2>
|
||||
<h2><a href="/event-apply">Apply for events.</a></h2>
|
||||
<h2><a href="/appeal">Appeal a punishment.</a></h2>
|
||||
</header>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user