Im struggling with SSR and CSR.
Tags: nextjs, react, mysql
Published: 2024-01-16 15:20:43

I want to create a storage management system for dentists. I don't seem to understand the concept of SSR and CSR and how to properly use it in my project. I have a route app/stock/page.tsx and this file has the "use client" tag. Though I am almost certain this is not the right way, it works. With which I struggle the most is the data fetching and the Next.js API routes. The API Routes just wont work for me when I add /app/stock/api/route.ts and write a GET handler. When i check with Postman I get Error 404.
I just need someone to tell me which functions or logic I should seperate into it's own file and why. 
On StackOverflow I just get downvotes and nobody wants to tell me what I'm doing wrong. Thank you in advance.

The code is as follows:

```
"use client";
import React, { useEffect, useState } from "react";
import "tailwindcss/tailwind.css";
import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable"
import { Button } from "@/components/ui/button"

const StockPage: React.FC = () => {
  const [items, setItems] = useState<any[]>([]);
  const [sortedItems, setSortedItems] = useState<any[]>([]);
  const [subcategories, setSubcategories] = useState<any[]>([]);
  const [selectedSubcategory, setSelectedSubcategory] = useState<any | null>(
    null
  );
  const [selectedItem, setSelectedItem] = useState<any | null>(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const res = await fetch("http://localhost:5000/get_items", {
          method: "GET",
          cache: "no-store",
        });
        const data = await res.json();
        setItems(data);
        setSortedItems(data);
      } catch (error) {
        console.error("Error fetching data:", error);
      }
    };

    fetchData();
  }, []);

  useEffect(() => {
    const fetchSubcategories = async () => {
      try {
        const res = await fetch("http://localhost:5000/get_subcategories", {
          method: "GET",
          cache: "no-store",
        });
        const data = await res.json();
        setSubcategories(data);
      } catch (error) {
        console.error("Error fetching subcategories:", error);
      }
    };

    fetchSubcategories();
  }, []);

  const handleSortBySubcategory = (selectedSubcategory: any) => {
    const sorted = items.filter((item) => item.subcategory === selectedSubcategory.id);
    setSortedItems(sorted);
    setSelectedSubcategory(selectedSubcategory);
  };
  
  const handleViewAll = () => {
    // Reset the sorting and display all items
    setSortedItems(items);
    setSelectedSubcategory(null);
  };

  const getSubcategoryName = (subcategoryId: string) => {
    const subcategory = subcategories.find(sub => sub.id === subcategoryId);
    return subcategory ? subcategory.name : "Unknown";
  };

  const handleRowClick = (item: any) => {
    // Toggle selection on row click
    setSelectedItem(selectedItem === item ? null : item);
  };

  const handleIncrementAmount = async () => {
    if (selectedItem) {
      // Make an API call to update the amount in the database
      try {
        const res = await fetch(`http://localhost:5000/updateAmount?id=${selectedItem.id}`, {
          method: 'PUT',
          cache: 'no-store',
        });

        if (res.ok) {
          // Update the amount in the local state only if the API call is successful
          const updatedItems = items.map((item) =>
            item.id === selectedItem.id
              ? { ...item, amount: item.amount + 1 }
              : item
          );

          // Update state to trigger a re-render
          setItems(updatedItems);
          setSortedItems(updatedItems);
        } else {
          console.error('Failed to update amount in the database');
        }
      } catch (error) {
        console.error('Error updating amount:', error);
      }
    }
  };

  const handleDecrementAmount = () => {
    if (selectedItem && selectedItem.amount > 0) {
      // Update the amount of the selected item by subtracting 1
      const updatedItems = items.map((item) =>
        item.id === selectedItem.id
          ? { ...item, amount: item.amount - 1 }
          : item
      );

      // Update state to trigger a re-render
      setItems(updatedItems);
      setSortedItems(updatedItems);
    }
  };


  return (
    <ResizablePanelGroup
      direction="horizontal"
      className="fit-w-md rounded-lg border"
    >
      <ResizablePanel defaultSize={50}>
        <div className="flex h-full items-center justify-center p-full">
        <table>
            <thead>
              <tr>
                <th>ID</th>
                <th>Name</th>
                <th>Subcategory</th>
                <th>Amount</th>
                <th>Limit</th>
                <th>Description</th>
                <th>TimestampE</th>
                <th>TimestampR</th>
              </tr>
            </thead>
            <tbody>
              {sortedItems.map((item) => (
                <tr
                  key={item.id}
                  onClick={() => handleRowClick(item)} // Handle row click
                  className={selectedItem === item ? "selected-row" : ""}
                >
                  <td>{item.id}</td>
                  <td>{item.name}</td>
                  <td>{getSubcategoryName(item.subcategory)}</td>
                  <td>{item.amount}</td>
                  <td>{item.limit}</td>
                  <td>{item.description}</td>
                  <td>{item.timestampE}</td>
                  <td>{item.timestampR}</td>
                </tr>
              ))}
            </tbody>
          </table>

            {selectedItem && (
              <p>Selected Row: {selectedItem.name}</p>
            )}
          
            {selectedSubcategory && (
              <p>Sorted by Subcategory: {selectedSubcategory.name}</p>
            )}
        </div>
      </ResizablePanel>
      <ResizableHandle />
      <ResizablePanel defaultSize={50}>
        <ResizablePanelGroup direction="vertical">
          <ResizablePanel defaultSize={25}>
            <div className="flex-wrap h-full items-center justify-center p-full">
              {subcategories.map((subcategory) => (
              <Button variant="custom"
                key={subcategory.id}
                onClick={() => handleSortBySubcategory(subcategory)}
              >
                {subcategory.name}
              </Button>
              ))}
              <Button variant="custom" onClick={handleViewAll}>View All</Button>
            </div>
          </ResizablePanel>
          <ResizableHandle />
          <ResizablePanel defaultSize={75}>
            <div className="flex h-full  justify-center p-full">
            {selectedItem ? (
              <>
                <div>
                  <p>Selected Row: {selectedItem.name}</p>
                  <p>Amount: {selectedItem.amount}</p>
                  {/* Add a button to increment amount */}
                  <Button onClick={handleIncrementAmount}>+</Button>
                  <Button onClick={handleDecrementAmount}>-</Button>
                </div>
              </>
            ) : null}
            </div>
          </ResizablePanel>
        </ResizablePanelGroup>
      </ResizablePanel>
    </ResizablePanelGroup>
  );
};

export default StockPage;
```