From 8fda5d9fb9e6e29a08cc9c54a96f887e34c613a8 Mon Sep 17 00:00:00 2001 From: Teriuihi Date: Sun, 6 Oct 2024 00:27:29 +0200 Subject: [PATCH] Initial appeal commit --- src/App.tsx | 2 + src/components/appeal.tsx | 21 +++++ src/components/form/data/appeal.tsx | 104 +++++++++++++++++++++ src/components/form/formActiveRedirect.tsx | 16 ++-- src/components/form/formData.tsx | 5 + src/components/form/formHTML.tsx | 24 ++++- src/components/form/formInterfaces.tsx | 3 +- src/components/home/home.tsx | 1 + 8 files changed, 167 insertions(+), 9 deletions(-) create mode 100644 src/components/appeal.tsx create mode 100644 src/components/form/data/appeal.tsx diff --git a/src/App.tsx b/src/App.tsx index 5598859..95e916d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -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() { ))} }/> }/> + }/> {process.env.NODE_ENV === 'development' && }/>} diff --git a/src/components/appeal.tsx b/src/components/appeal.tsx new file mode 100644 index 0000000..bf4be87 --- /dev/null +++ b/src/components/appeal.tsx @@ -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 ( +
+ + Appeals Selection + + +
+

Welcome to the Appeals page

+

Appeal a Minecraft punishment.

+

Appeal a Discord punishment.

+
+
+ ); +} + +export default Appeal; \ No newline at end of file diff --git a/src/components/form/data/appeal.tsx b/src/components/form/data/appeal.tsx new file mode 100644 index 0000000..42c2815 --- /dev/null +++ b/src/components/form/data/appeal.tsx @@ -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 => { + 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", +}; \ No newline at end of file diff --git a/src/components/form/formActiveRedirect.tsx b/src/components/form/formActiveRedirect.tsx index 50e29d2..fa46ee9 100644 --- a/src/components/form/formActiveRedirect.tsx +++ b/src/components/form/formActiveRedirect.tsx @@ -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(() => { diff --git a/src/components/form/formData.tsx b/src/components/form/formData.tsx index bd66218..7308284 100644 --- a/src/components/form/formData.tsx +++ b/src/components/form/formData.tsx @@ -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[] { diff --git a/src/components/form/formHTML.tsx b/src/components/form/formHTML.tsx index c9aff04..8699637 100644 --- a/src/components/form/formHTML.tsx +++ b/src/components/form/formHTML.tsx @@ -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 = ({ const [selectedOptions, setSelectedOptions] = useState(fieldValues); + const [options, setOptions] = useState([]); + + 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 ( = ({ {option} ))} + {options.map((option, i) => ( + + ))} + {options.length === 0 ? "

No data found, please check if your username is valid. Or if this was a discord punishment, please use the discord appeal form

":"

"} ); } else { diff --git a/src/components/form/formInterfaces.tsx b/src/components/form/formInterfaces.tsx index 2dffa1a..0af2b19 100644 --- a/src/components/form/formInterfaces.tsx +++ b/src/components/form/formInterfaces.tsx @@ -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; } export interface UserInput { diff --git a/src/components/home/home.tsx b/src/components/home/home.tsx index 3253897..7254a47 100644 --- a/src/components/home/home.tsx +++ b/src/components/home/home.tsx @@ -13,6 +13,7 @@ const Home: FunctionComponent = () => {

Contact us.

Apply for staff.

Apply for events.

+

Appeal a punishment.

);