Parcourir la source

Introduce Settings page

Tatiana Inama il y a 4 ans
Parent
commit
e112e5d00a

+ 13 - 21
components/Nav.tsx

@@ -1,10 +1,6 @@
 import { FC } from "react";
 
-type NavTypes = {
-  SecondaryNavigation?: FC;
-};
-
-const Nav: FC<NavTypes> = ({ SecondaryNavigation }) => (
+const Nav: FC = () => (
   <header className="bg-prisma-50 w-full min-h-nav flex items-end">
     <nav className="w-full max-w-screen-lg flex mx-auto justify-between">
       <ul className="flex">
@@ -14,22 +10,18 @@ const Nav: FC<NavTypes> = ({ SecondaryNavigation }) => (
           </a>
         </li>
       </ul>
-      {SecondaryNavigation ? (
-        <SecondaryNavigation />
-      ) : (
-        <ul className="flex">
-          <li className="">
-            <a href="#" className="py-7 px-4 block">
-              Sign up
-            </a>
-          </li>
-          <li className="">
-            <a href="#" className="py-7 px-4 block">
-              Log in
-            </a>
-          </li>
-        </ul>
-      )}
+      <ul className="flex">
+        <li className="">
+          <a href="#" className="py-7 px-4 block">
+            Sign up
+          </a>
+        </li>
+        <li className="">
+          <a href="#" className="py-7 px-4 block">
+            Log in
+          </a>
+        </li>
+      </ul>
     </nav>
   </header>
 );

+ 3 - 1
hooks/useForm.ts

@@ -3,6 +3,7 @@ import { FormEventHandler, useState } from "react";
 
 type useFormProps = {
   path: ApiPaths;
+  query?: string;
   method: ApiMethods;
 };
 
@@ -10,7 +11,7 @@ type FormMessage = {
   message: string;
 };
 
-const useForm = ({ path, method }: useFormProps) => {
+const useForm = ({ path, method, query }: useFormProps) => {
   const [error, setError] = useState<FormMessage>();
   const [loading, setLoading] = useState(false);
   const [success, setSuccess] = useState<FormMessage>();
@@ -21,6 +22,7 @@ const useForm = ({ path, method }: useFormProps) => {
     const formData = new FormData(event.currentTarget);
     const { error, message } = await fetchApi({
       path,
+      query,
       method,
       body: Object.fromEntries(formData.entries()),
     });

+ 4 - 6
pages/api/login.ts

@@ -14,12 +14,10 @@ const loginHandler: NextApiHandler = async (req, res) => {
       if (axios.isAxiosError(e)) {
         res.status(e.response?.status || 500).json(e.response?.data);
       } else {
-        res
-          .status(500)
-          .json({
-            message:
-              "There was an error processing the request, please try again.",
-          });
+        res.status(500).json({
+          message:
+            "There was an error processing the request, please try again.",
+        });
       }
     }
   }

+ 3 - 6
pages/api/signup.ts

@@ -16,12 +16,9 @@ const signUpHandler: NextApiHandler = async (req, res) => {
       console.error(
         `Error while trying to register: ${JSON.stringify(req.body, null, 2)}`
       );
-      res
-        .status(500)
-        .json({
-          message:
-            "There was an error processing the request, please try again.",
-        });
+      res.status(500).json({
+        message: "There was an error processing the request, please try again.",
+      });
     }
   }
 };

+ 27 - 0
pages/api/user/[id].ts

@@ -0,0 +1,27 @@
+import axios from "axios";
+import type { NextApiHandler } from "next";
+
+const userUpdate: NextApiHandler = async (req, res) => {
+  const { id } = req.query;
+  try {
+    const response = await axios.put(
+      `${process.env.PRISMA_API}/user/${id}`,
+      req.body,
+      { headers: { "Content-Type": "application/json" } }
+    );
+    res.status(response.status).json(response.data);
+  } catch (e) {
+    if (axios.isAxiosError(e)) {
+      res.status(e.response?.status || 500).json(e.response?.data);
+    } else {
+      res
+        .status(500)
+        .json({
+          message:
+            "There was an error processing the request, please try again.",
+        });
+    }
+  }
+};
+
+export default userUpdate;

+ 7 - 0
pages/api/user/index.ts

@@ -0,0 +1,7 @@
+import { NextApiHandler } from "next";
+
+const userHandler: NextApiHandler = async (req, res) => {
+  res.status(200).json({ message: "Mock endpoind" });
+};
+
+export default userHandler;

+ 3 - 6
pages/login.tsx

@@ -12,7 +12,7 @@ const Login: NextPage = () => {
   return (
     <Layout>
       <form className="form" onSubmit={submitHandler}>
-        <div className="xs:contents">
+        <div className="form-group">
           <label htmlFor="email" className="form-label">
             Email
           </label>
@@ -25,7 +25,7 @@ const Login: NextPage = () => {
             required
           />
         </div>
-        <div className="xs:contents">
+        <div className="form-group">
           <label htmlFor="password" className="form-label">
             Password
           </label>
@@ -42,10 +42,7 @@ const Login: NextPage = () => {
           Log in
         </button>
         {error && (
-          <div
-            role="alert"
-            className="col-span-2 bg-red-200 p-4 text-center rounded font-bold text-red-900"
-          >
+          <div role="alert" className="form-alert-msg">
             {error.message}
           </div>
         )}

+ 90 - 0
pages/settings.tsx

@@ -0,0 +1,90 @@
+import { NextPage } from "next/types";
+import Layout from "../components/Layout";
+import useForm from "../hooks/useForm";
+import { ApiPaths, ApiMethods } from "../utils/api";
+
+const Settings: NextPage = () => {
+  const user = {
+    id: 4,
+    name: "Monkey",
+    email: "monkey@gmail.com",
+    password: "123456",
+    team: "Admins",
+  };
+
+  const { error, submitHandler } = useForm({
+    path: ApiPaths.Settings,
+    query: JSON.stringify(user.id),
+    method: ApiMethods.PUT,
+  });
+
+  return (
+    <Layout>
+      <form className="form" onSubmit={submitHandler}>
+        <div className="form-group">
+          <label htmlFor="name" className="form-label">
+            Name
+          </label>
+          <input
+            type="text"
+            name="name"
+            id="name"
+            className="form-input"
+            defaultValue={user.name}
+          />
+        </div>
+        <div className="form-group">
+          <label htmlFor="email" className="form-label">
+            Email
+          </label>
+          <input
+            type="email"
+            name="email"
+            id="email"
+            className="form-input"
+            defaultValue={user.email}
+          />
+        </div>
+        <div className="form-group">
+          <label htmlFor="password" className="form-label">
+            Password
+          </label>
+          <input
+            type="password"
+            id="password"
+            name="password"
+            className="form-input"
+            defaultValue={user.password}
+            minLength={6}
+          />
+        </div>
+        <div className="form-group">
+          <label htmlFor="team" className="form-label">
+            Team
+          </label>
+          <select
+            className="form-input"
+            id="team"
+            name="team"
+            defaultValue={user.team}
+          >
+            <option value="Admins">Admins</option>
+            <option value="Users">Users</option>
+            <option value="Viewers">Viewers</option>
+          </select>
+        </div>
+        <input type="hidden" id="id" name="id" value={user.id} />
+        <button type="submit" className="form-button">
+          Save
+        </button>
+        {error && (
+          <div role="alert" className="form-alert-msg">
+            {error.message}
+          </div>
+        )}
+      </form>
+    </Layout>
+  );
+};
+
+export default Settings;

+ 3 - 6
pages/signup.tsx

@@ -12,7 +12,7 @@ const SignUp: NextPage = () => {
   return (
     <Layout>
       <form className="form" onSubmit={submitHandler}>
-        <div className="xs:contents">
+        <div className="form-group">
           <label htmlFor="email" className="form-label">
             Email
           </label>
@@ -25,7 +25,7 @@ const SignUp: NextPage = () => {
             required
           />
         </div>
-        <div className="xs:contents">
+        <div className="form-group">
           <label htmlFor="password" className="form-label">
             Password
           </label>
@@ -43,10 +43,7 @@ const SignUp: NextPage = () => {
           Sign up
         </button>
         {error && (
-          <div
-            role="alert"
-            className="col-span-2 bg-red-200 p-4 text-center rounded font-bold text-red-900"
-          >
+          <div role="alert" className="form-alert-msg">
             {error.message}
           </div>
         )}

+ 8 - 0
styles/globals.css

@@ -25,6 +25,10 @@
     @apply w-full max-w-screen-xs mx-auto flex flex-col xs:grid xs:grid-cols-form xs:items-center gap-4;
   }
 
+  .form-group {
+    @apply xs:contents;
+  }
+
   .form-label {
     @apply font-bold flex-1 xs:text-right;
   }
@@ -36,4 +40,8 @@
   .form-button {
     @apply col-start-2 w-max py-2 px-4 bg-prisma-900 text-white font-bold rounded text-sm hover:bg-prisma-800 active:bg-prisma-700;
   }
+
+  .form-alert-msg {
+    @apply col-span-2 bg-red-200 p-4 text-center rounded font-bold text-red-900;
+  }
 }

+ 6 - 2
utils/api.ts

@@ -1,16 +1,19 @@
 export enum ApiMethods {
   GET = "GET",
   POST = "POST",
+  PUT = "PUT",
 }
 
 export enum ApiPaths {
   SignUp = "signup",
   Login = "login",
+  Settings = "user",
 }
 
 type FetchApiProps<T> = {
   method: ApiMethods;
   path: ApiPaths;
+  query?: string;
   body: T;
 };
 
@@ -19,9 +22,10 @@ type FetchApiResult = { error?: string; message?: string };
 const fetchApi = async <T>({
   method,
   path,
+  query,
   body,
 }: FetchApiProps<T>): Promise<FetchApiResult> => {
-  const response = await fetch(`/api/${path}`, {
+  const response = await fetch(`/api/${path}/${query || ""}`, {
     method: method,
     body: JSON.stringify(body),
   });
@@ -32,7 +36,7 @@ const fetchApi = async <T>({
     return { message };
   } else {
     return {
-      error: message,
+      error: message.replace("Incorect", "Incorrect"),
     };
   }
 };