diff --git a/frontend/app/layout.tsx b/frontend/app/layout.tsx
index 8436098..b650ede 100644
--- a/frontend/app/layout.tsx
+++ b/frontend/app/layout.tsx
@@ -1,6 +1,7 @@
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
+import {Toaster} from "@/components/ui/sonner";
const inter = Inter({ subsets: ["latin"] });
@@ -17,6 +18,7 @@ export default function RootLayout({
return (
{children}
+
);
}
diff --git a/frontend/app/registration/page.tsx b/frontend/app/registration/page.tsx
index 90c63d1..c8fedd2 100644
--- a/frontend/app/registration/page.tsx
+++ b/frontend/app/registration/page.tsx
@@ -2,6 +2,11 @@
import { useRouter } from "next/navigation";
import {
+ AddStudentApplicationForEventDocument,
+ AddStudentApplicationForEventMutation,
+ AddStudentApplicationForEventMutationVariables,
+ NewQuestionResponsePair,
+ NewUserToEventApplication,
QuestionType,
RegistrationFormDocument,
RegistrationFormQuery,
@@ -32,6 +37,7 @@ import {
FormItem,
FormMessage,
} from "@/components/ui/form";
+import { Toaster, toast } from "sonner";
type Props = {
searchParams: {
@@ -66,11 +72,17 @@ const Home = ({ searchParams }: Props) => {
const [index, setIndex] = useState(0);
const [loading, setLoading] = useState(true);
const router = useRouter();
+ const [responses, setResponses] = useState([]);
useEffect(() => {
- const fetchData = async () => {
- const eventID = searchParams.e;
+ if (responses.length > 0) {
+ onSubmit();
+ }
+ }, [responses]);
+ const eventID = searchParams.e;
+ useEffect(() => {
+ const fetchData = async () => {
const vars: RegistrationFormQueryVariables = {
eventID: parseInt(eventID),
};
@@ -92,7 +104,7 @@ const Home = ({ searchParams }: Props) => {
};
fetchData();
- }, [searchParams.e, router]);
+ }, [router]);
useEffect(() => {
if (regForm) {
@@ -101,14 +113,18 @@ const Home = ({ searchParams }: Props) => {
}, [index, regForm]);
const mcForm = useForm>>({
- resolver: zodResolver(MultipleChoiceFormSchema(regForm?.questions[index].required!)),
+ resolver: zodResolver(
+ MultipleChoiceFormSchema(regForm?.questions[index].required!)
+ ),
defaultValues: {
multipleChoice: [],
},
});
const scForm = useForm>>({
- resolver: zodResolver(SingleChoiceFormSchema(regForm?.questions[index].required!)),
+ resolver: zodResolver(
+ SingleChoiceFormSchema(regForm?.questions[index].required!)
+ ),
defaultValues: {
singleChoice: undefined,
},
@@ -118,36 +134,79 @@ const Home = ({ searchParams }: Props) => {
router.push("/");
}
- const FooterButtons = () => (
-
-
-
-
- );
-
- function onSubmit() {
+ const onSubmit = async () => {
if (regForm?.questions.length !== index + 1) {
setIndex((prevIndex) => prevIndex + 1);
+ return;
}
- }
+
+ await new Promise((resolve) => setTimeout(resolve, 250));
+
+ const application: NewUserToEventApplication = {
+ // TODO
+ userMail: "tutor1@example.de",
+ eventID: +eventID,
+ answers: responses,
+ };
+
+ const vars: AddStudentApplicationForEventMutationVariables = {
+ application: application,
+ };
+
+ try {
+ await client.request(
+ AddStudentApplicationForEventDocument,
+ vars
+ );
+ toast("Anmeldung abgeschickt!");
+ handleQuit();
+ } catch (err) {
+ toast("Ein Fehler ist aufgetreten");
+ console.error(err)
+ }
+ };
function onScaleSubmit() {
- onSubmit();
+ const res: NewQuestionResponsePair = {
+ questionID: regForm?.questions[index].ID || 0,
+ value: String(sliderValue),
+ };
+ setResponses((prevResponses) => [...prevResponses, res]);
+
setSliderValue(0);
}
- function onMCSubmit(data: z.infer>) {
- onSubmit();
+ function onMCSubmit(
+ data: z.infer>
+ ) {
+ const newResponses = data.multipleChoice!.map((id) => ({
+ questionID: regForm?.questions[index].ID || 0,
+ answerID: id,
+ }));
+ setResponses((prevResponses) => [...prevResponses, ...newResponses]);
}
- function onSCSubmit(data: z.infer>) {
- onSubmit();
+ function onSCSubmit(
+ data: z.infer>
+ ) {
+ const res: NewQuestionResponsePair = {
+ questionID: regForm?.questions[index].ID || 0,
+ answerID: data.singleChoice!,
+ };
+ setResponses((prevResponses) => [...prevResponses, res]);
}
+ const FooterButtons = () => (
+
+
+
+
+ );
+
if (loading) {
return Loading...
;
}
@@ -195,7 +254,7 @@ const Home = ({ searchParams }: Props) => {
onCheckedChange={(checked) => {
return checked
? field.onChange([
- ...field.value || [],
+ ...(field.value || []),
answer.ID,
])
: field.onChange(
diff --git a/frontend/components/ui/sonner.tsx b/frontend/components/ui/sonner.tsx
new file mode 100644
index 0000000..452f4d9
--- /dev/null
+++ b/frontend/components/ui/sonner.tsx
@@ -0,0 +1,31 @@
+"use client"
+
+import { useTheme } from "next-themes"
+import { Toaster as Sonner } from "sonner"
+
+type ToasterProps = React.ComponentProps
+
+const Toaster = ({ ...props }: ToasterProps) => {
+ const { theme = "system" } = useTheme()
+
+ return (
+
+ )
+}
+
+export { Toaster }
diff --git a/frontend/lib/gql/generated/gql.ts b/frontend/lib/gql/generated/gql.ts
index 163e602..c2316b3 100644
--- a/frontend/lib/gql/generated/gql.ts
+++ b/frontend/lib/gql/generated/gql.ts
@@ -13,9 +13,10 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/
* Therefore it is highly recommended to use the babel or swc plugin for production.
*/
const documents = {
+ "mutation addStudentApplicationForEvent($application: NewUserToEventApplication!) {\n addStudentApplicationForEvent(application: $application) {\n fn\n }\n}": types.AddStudentApplicationForEventDocument,
"mutation addTutor($firstName: String!, $lastName: String!, $email: String!, $eventsAvailable: [Int!]!) {\n addTutor(\n tutor: {fn: $firstName, sn: $lastName, mail: $email}\n availability: {userMail: $email, eventID: $eventsAvailable}\n ) {\n fn\n }\n}": types.AddTutorDocument,
"query tutorFormEvents {\n events(needsTutors: true, onlyFuture: true) {\n ID\n title\n from\n to\n topic {\n name\n color\n }\n type {\n name\n color\n }\n }\n}": types.TutorFormEventsDocument,
- "query registrationForm($eventID: Int!) {\n forms(id: [$eventID]) {\n title\n description\n questions {\n title\n type\n required\n answers {\n ID\n title\n points\n }\n }\n }\n}": types.RegistrationFormDocument,
+ "query registrationForm($eventID: Int!) {\n forms(id: [$eventID]) {\n title\n description\n questions {\n ID\n title\n type\n required\n answers {\n ID\n title\n points\n }\n }\n }\n}": types.RegistrationFormDocument,
};
/**
@@ -32,6 +33,10 @@ const documents = {
*/
export function graphql(source: string): unknown;
+/**
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
+ */
+export function graphql(source: "mutation addStudentApplicationForEvent($application: NewUserToEventApplication!) {\n addStudentApplicationForEvent(application: $application) {\n fn\n }\n}"): (typeof documents)["mutation addStudentApplicationForEvent($application: NewUserToEventApplication!) {\n addStudentApplicationForEvent(application: $application) {\n fn\n }\n}"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
@@ -43,7 +48,7 @@ export function graphql(source: "query tutorFormEvents {\n events(needsTutors:
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
-export function graphql(source: "query registrationForm($eventID: Int!) {\n forms(id: [$eventID]) {\n title\n description\n questions {\n title\n type\n required\n answers {\n ID\n title\n points\n }\n }\n }\n}"): (typeof documents)["query registrationForm($eventID: Int!) {\n forms(id: [$eventID]) {\n title\n description\n questions {\n title\n type\n required\n answers {\n ID\n title\n points\n }\n }\n }\n}"];
+export function graphql(source: "query registrationForm($eventID: Int!) {\n forms(id: [$eventID]) {\n title\n description\n questions {\n ID\n title\n type\n required\n answers {\n ID\n title\n points\n }\n }\n }\n}"): (typeof documents)["query registrationForm($eventID: Int!) {\n forms(id: [$eventID]) {\n title\n description\n questions {\n ID\n title\n type\n required\n answers {\n ID\n title\n points\n }\n }\n }\n}"];
export function graphql(source: string) {
return (documents as any)[source] ?? {};
diff --git a/frontend/lib/gql/generated/graphql.ts b/frontend/lib/gql/generated/graphql.ts
index d0cee9b..6f4a3b6 100644
--- a/frontend/lib/gql/generated/graphql.ts
+++ b/frontend/lib/gql/generated/graphql.ts
@@ -25,6 +25,22 @@ export type Answer = {
title: Scalars['String']['output'];
};
+export type AnswerValuePair = {
+ __typename?: 'AnswerValuePair';
+ answer?: Maybe;
+ value?: Maybe;
+};
+
+export type Application = {
+ __typename?: 'Application';
+ accepted?: Maybe;
+ event: Event;
+ form: Form;
+ responses?: Maybe>;
+ score: Scalars['Int']['output'];
+ student: User;
+};
+
export type Building = {
__typename?: 'Building';
ID: Scalars['Int']['output'];
@@ -96,6 +112,8 @@ export type Mutation = {
addRoom: Room;
addRoomAvailabilityForEvent: Room;
addSetting: Setting;
+ addStudent: User;
+ addStudentApplicationForEvent: User;
addStudentRegistrationForEvent: User;
addTutor: User;
addTutorAvailabilityForEvent: User;
@@ -108,6 +126,7 @@ export type Mutation = {
deleteRoom: Scalars['Int']['output'];
deleteRoomAvailabilityForEvent: Room;
deleteSetting: Scalars['Int']['output'];
+ deleteStudentApplicationForEvent: User;
deleteStudentRegistrationForEvent: User;
deleteTutorAvailabilityForEvent: User;
deleteUser: Scalars['Int']['output'];
@@ -161,6 +180,17 @@ export type MutationAddSettingArgs = {
};
+export type MutationAddStudentArgs = {
+ application: NewUserToEventApplication;
+ student: NewUser;
+};
+
+
+export type MutationAddStudentApplicationForEventArgs = {
+ application: NewUserToEventApplication;
+};
+
+
export type MutationAddStudentRegistrationForEventArgs = {
registration: UserToEventRegistration;
};
@@ -223,6 +253,12 @@ export type MutationDeleteSettingArgs = {
};
+export type MutationDeleteStudentApplicationForEventArgs = {
+ eventID: Scalars['Int']['input'];
+ mail: Scalars['String']['input'];
+};
+
+
export type MutationDeleteStudentRegistrationForEventArgs = {
registration: UserToEventRegistration;
};
@@ -314,11 +350,17 @@ export type NewLabel = {
export type NewQuestion = {
answers: Array;
- required?: InputMaybe;
+ required: Scalars['Boolean']['input'];
title: Scalars['String']['input'];
type: QuestionType;
};
+export type NewQuestionResponsePair = {
+ answerID?: InputMaybe;
+ questionID: Scalars['Int']['input'];
+ value?: InputMaybe;
+};
+
export type NewRoom = {
buildingID: Scalars['Int']['input'];
capacity?: InputMaybe;
@@ -340,6 +382,12 @@ export type NewUser = {
sn?: InputMaybe;
};
+export type NewUserToEventApplication = {
+ answers?: InputMaybe>;
+ eventID: Scalars['Int']['input'];
+ userMail: Scalars['String']['input'];
+};
+
export type NewUserToEventAvailability = {
eventID: Array;
userMail: Scalars['String']['input'];
@@ -347,6 +395,7 @@ export type NewUserToEventAvailability = {
export type Query = {
__typename?: 'Query';
+ applications: Array;
buildings: Array;
events: Array;
forms: Array