From 363936641a31b0b508197d41bea1ce116931b5d4 Mon Sep 17 00:00:00 2001
From: Paweł Bernaciak <pawelbernaciak@zohomail.eu>
Date: Sat, 20 Jan 2024 11:03:44 +0100
Subject: New element creator

---
 frontend/src/components/ElementCreator.tsx | 203 +++++++++++++++++++++++++++++
 1 file changed, 203 insertions(+)
 create mode 100644 frontend/src/components/ElementCreator.tsx

(limited to 'frontend/src/components/ElementCreator.tsx')

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;
-- 
cgit v1.2.3

