DEV Community

Roberto Luna
Roberto Luna

Posted on

Implementing Calculators and Checklist Features with a Clean Sidebar

Implementing Calculators and Checklist Features with a Clean Sidebar

TL;DR: I added calculator and checklist tools to the Riviera Industrial ERP, along with a cleaned-up sidebar. This involved updating several components, adding new files, and configuring environment variables.

The Problem

The Riviera Industrial ERP needed additional tools to enhance user productivity. Specifically, we required engineering calculators and a diagnostic checklist. The sidebar also needed a redesign for better navigation.

What I Tried First

Initially, I attempted to integrate the calculator and checklist features into existing components. However, this approach led to code clutter and made maintenance more difficult. I realized that creating separate components for each tool would be a better approach.

The Implementation

Environment Variables

I started by updating the .env file to include a ClickUp API key:

# .env
SUPABASE_BUCKET="riviera-docs"

# Test helpers
DISABLE_RATE_LIMIT=true

# ClickUp
CLICKUP_API_KEY=pk_204263176_CAJOXIE5XPFY5D5TYMXTQKQMZH0EGC5K
Enter fullscreen mode Exit fullscreen mode

This change allows us to use the ClickUp API for future integrations.

Calculator Component

Next, I created a new component for the calculator feature in src/components/shared/CalculatorApp.tsx:

// src/components/shared/CalculatorApp.tsx
"use client";
import { useState } from "react";

// ── Tipos ──────────────────────────────────────────────────────────────────────
type CalcId = "tolerancias" | "ajustes" | "velocidad";

const calculators: Record<CalcId, (inputs: any) => number> = {
  tolerancias: (inputs) => inputs.length * 0.01,
  ajustes: (inputs) => inputs.width * inputs.height,
  velocidad: (inputs) => inputs.distance / inputs.time,
};

const CalculatorApp = () => {
  const [calcId, setCalcId] = useState<CalcId>("tolerancias");
  const [inputs, setInputs] = useState({ length: 0 });

  const handleCalcChange = (id: CalcId) => {
    setCalcId(id);
  };

  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setInputs({ ...inputs, [e.target.name]: e.target.value });
  };

  const result = calculators[calcId](inputs);

  return (
    <div>
      <select value={calcId} onChange={(e) => handleCalcChange(e.target.value as CalcId)}>
        {Object.keys(calculators).map((id) => (
          <option key={id} value={id}>
            {id}
          </option>
        ))}
      </select>
      <input type="number" name="length" value={inputs.length} onChange={handleInputChange} />
      <p>Result: {result}</p>
    </div>
  );
};

export default CalculatorApp;
Enter fullscreen mode Exit fullscreen mode

This component allows users to select a calculator type and input values to get a result.

Checklist Component

Similarly, I created a new component for the checklist feature in src/components/shared/ChecklistApp.tsx:

// src/components/shared/ChecklistApp.tsx
"use client";
import { useState } from "react";

type CheckItem = { id: string; label: string; required?: boolean };
type Section = { id: string; icon: string; title: string; items: CheckItem[] };

const checklist: Section[] = [
  {
    id: "section1",
    icon: "📝",
    title: "Section 1",
    items: [
      { id: "item1", label: "Item 1", required: true },
      { id: "item2", label: "Item 2" },
    ],
  },
];

const ChecklistApp = () => {
  const [checkedItems, setCheckedItems] = useState<Record<string, boolean>>({});

  const handleCheckChange = (itemId: string) => {
    setCheckedItems((prev) => ({ ...prev, [itemId]: !prev[itemId] }));
  };

  return (
    <div>
      {checklist.map((section) => (
        <div key={section.id}>
          <h2>{section.title}</h2>
          <ul>
            {section.items.map((item) => (
              <li key={item.id}>
                <input
                  type="checkbox"
                  checked={checkedItems[item.id] || false}
                  onChange={() => handleCheckChange(item.id)}
                />
                <span>{item.label}</span>
              </li>
            ))}
          </ul>
        </div>
      ))}
    </div>
  );
};

export default ChecklistApp;
Enter fullscreen mode Exit fullscreen mode

This component displays a checklist with sections and items, allowing users to check and uncheck items.

Sidebar Updates

I updated the Sidebar.tsx component to include links to the new calculator and checklist features:

// src/components/layout/Sidebar.tsx
const NAV_ALL = [
  // ...
  { section: "Herramientas", items: [
    { href: "/tools/calculators", icon: "📊", label: "Calculadoras" },
    { href: "/tools/checklist", icon: "📝", label: "Checklist" },
  ]},
];
Enter fullscreen mode Exit fullscreen mode

Page Updates

Finally, I updated the page.tsx files for the calculator and checklist features:

// src/app/tools/calculators/page.tsx
import { PageHeader } from "@/components/shared/PageHeader";
import CalculatorApp from "@/components/shared/CalculatorApp";

export default function CalculatorsPage() {
  return (
    <div>
      <PageHeader title="Calculadoras" />
      <CalculatorApp />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode
// src/app/tools/checklist/page.tsx
import { PageHeader } from "@/components/shared/PageHeader";
import ChecklistApp from "@/components/shared/ChecklistApp";

export default function ChecklistPage() {
  return (
    <div>
      <PageHeader title="Checklist" />
      <ChecklistApp />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Key Takeaway

The key takeaway from this implementation is the importance of breaking down complex features into separate, reusable components. This approach makes maintenance and updates easier, allowing for a more scalable and efficient development process.

What's Next

Next, I plan to integrate the ClickUp API to enhance the checklist feature with task management capabilities. This will involve updating the ChecklistApp component to use the ClickUp API for creating and managing tasks.


Part of my Build in Public series — sharing the real process of building Building Riviera Industrial ERP from Playa del Carmen, México.

Repo: zaerohell/riviera-industrial-erp · 2026-07-06

#playadev #buildinpublic

Top comments (0)