summaryrefslogtreecommitdiff
path: root/frontend/src/components/ElementCreator.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/components/ElementCreator.tsx')
-rw-r--r--frontend/src/components/ElementCreator.tsx203
1 files changed, 203 insertions, 0 deletions
diff --git a/frontend/src/components/ElementCreator.tsx b/frontend/src/components/ElementCreator.tsx
new file mode 100644
index 0000000..61f5aba
--- /dev/null
+++ b/frontend/src/components/ElementCreator.tsx
@@ -0,0 +1,203 @@
+import { FC, useEffect, useState } from 'react';
+import {
+ Element,
+ Color,
+ ColorBitmap,
+ ElementState,
+ ElementSuggestion,
+ ColorCode,
+} from '../types';
+import toast from 'react-hot-toast';
+import ElementView from './ElementView';
+import { userStore } from '../stores';
+
+interface ElementCreatorProps {
+ firstElementId: number | undefined;
+ secondElementId: number | undefined;
+ closeDialog: () => void;
+}
+
+const ElementCreator: FC<ElementCreatorProps> = ({
+ firstElementId,
+ secondElementId,
+ closeDialog,
+}) => {
+ const [elementName, setElementName] = useState<string>('');
+ const [color, setColor] = useState<Color>(Color.Air);
+ const [firstElement, setFirstElement] = useState<Element | null>(null);
+ const [secondElement, setSecondElement] = useState<Element | null>(null);
+ const setUser = userStore((store) => store.setUser);
+
+ const fetchElement = async (elementId: number): Promise<Element> => {
+ const elementResponse = await fetch(`/api/element/${elementId}`);
+ return await elementResponse.json();
+ };
+
+ useEffect(() => {
+ if (firstElementId == undefined || secondElementId == undefined) {
+ return;
+ }
+
+ setElementName('');
+ setColor(Color.Air);
+
+ fetchElement(firstElementId).then((elem) => {
+ setFirstElement(elem);
+ });
+ fetchElement(secondElementId).then((elem) => {
+ setSecondElement(elem);
+ });
+ }, [firstElementId, secondElementId]);
+
+ const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+ setElementName(e.target.value);
+ };
+
+ const createHandleColorClick = (color: Color) => {
+ return (e: React.MouseEvent<HTMLButtonElement>) => {
+ e.preventDefault();
+ setColor(color);
+ };
+ };
+
+ const handleSubmitButton = async (e: React.MouseEvent<HTMLButtonElement>) => {
+ e.preventDefault();
+
+ if (elementName == '') {
+ toast.error('No name selected');
+ return;
+ }
+ if (!(color in Color)) {
+ toast.error('Bad color value');
+ return;
+ }
+
+ const request: ElementSuggestion = {
+ name: elementName,
+ iconBitmap: ColorBitmap[color],
+ firstElementId: firstElementId!,
+ secondElementId: secondElementId!,
+ };
+
+ console.log(request);
+
+ const createVoteResponse = await fetch(`/api/suggestion/create`, {
+ method: 'POST',
+ credentials: 'include',
+ body: JSON.stringify(request),
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+
+ if (createVoteResponse.status == 401) {
+ console.log('Session expired');
+ toast.error('Your authorization has expired. You have to log in again.');
+ localStorage.removeItem('user');
+ setUser(undefined);
+ return;
+ }
+ console.log(createVoteResponse.status);
+ console.log('Vote started');
+ closeDialog();
+ };
+
+ return (
+ <form className="flex flex-col items-center">
+ <div className="flex items-center">
+ {firstElement != null && secondElement != null && (
+ <>
+ <ElementView
+ element={firstElement!}
+ onElementCombine={() => {}}
+ isPreview={false}
+ interactive={false}
+ />
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 24 24"
+ strokeWidth={1.5}
+ stroke="currentColor"
+ className="w-6 h-6">
+ <path
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ d="M12 4.5v15m7.5-7.5h-15"
+ />
+ </svg>
+ <ElementView
+ element={secondElement!}
+ onElementCombine={() => {}}
+ isPreview={false}
+ interactive={false}
+ />
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 24 24"
+ strokeWidth={1.5}
+ stroke="currentColor"
+ className="w-6 h-6">
+ <path
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ d="M3.75 9h16.5m-16.5 6.75h16.5"
+ />
+ </svg>
+ </>
+ )}
+ <ElementView
+ element={{
+ name: elementName,
+ icon: ColorCode[color],
+ id: 0,
+ userId: 0,
+ state: ElementState.HasColor,
+ }}
+ onElementCombine={() => {}}
+ isPreview={true}
+ interactive={false}
+ />
+ </div>
+ <div className="mb-5 w-full">
+ <label
+ htmlFor="element-name"
+ className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
+ Element name
+ </label>
+ <input
+ type="text"
+ id="element-name"
+ value={elementName}
+ onChange={handleNameChange}
+ className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
+ required
+ />
+ </div>
+ <div className="flex flex-wrap mb-3 gap-2 border p-2 rounded shadow justify-center">
+ {(Object.keys(Color) as Array<keyof typeof Color>)
+ .filter((color) => Number.isNaN(Number(color)))
+ .map((color) => {
+ return (
+ <button
+ key={color}
+ onClick={createHandleColorClick(Color[color])}>
+ <div
+ className="border border-gray-200 w-8 h-8"
+ style={{ backgroundColor: ColorCode[Color[color]] }}></div>
+ </button>
+ );
+ })}
+ </div>
+ <button
+ onClick={handleSubmitButton}
+ type="submit"
+ className=" text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
+ Submit
+ </button>
+ </form>
+ );
+};
+
+export default ElementCreator;