https://github.com/nyaomaru/technical-debt-sample
Technical debt sample for order form
https://github.com/nyaomaru/technical-debt-sample
nextjs react react-hook-form refactoring sample-project shadcn-ui tailwindcss technical-debt typescript zod
Last synced: about 2 months ago
JSON representation
Technical debt sample for order form
- Host: GitHub
- URL: https://github.com/nyaomaru/technical-debt-sample
- Owner: nyaomaru
- Created: 2025-06-01T11:28:35.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2025-06-10T10:57:38.000Z (12 months ago)
- Last Synced: 2025-06-10T11:41:33.635Z (12 months ago)
- Topics: nextjs, react, react-hook-form, refactoring, sample-project, shadcn-ui, tailwindcss, technical-debt, typescript, zod
- Language: TypeScript
- Homepage: https://technical-debt-sample.vercel.app
- Size: 310 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Technical Debt Sample
This repository demonstrates how to refactor a form component suffering from technical debt.
It is built with `Next.js` (App Router), `zod`, `React Hook Form (RHF)`, and `shadcn/ui`.
---
## Philosophy
- Feature-based architecture with App Router
- Form validation using `zod`
- Form logic implemented using `react-hook-form`
- UI styled with `tailwindcss` and `shadcn/ui` components
---
## Problem
Imagine you created a bloated `OrderForm` component like this:
Click to expand code sample
```tsx
import { useState, useEffect } from 'react';
import {
stepOneSchema,
stepTwoSchema,
stepThreeSchema,
stepFourSchema,
} from './formSchema';
type Form = {
customerName: string; // Step1
email: string; // Step1
phone: string; // Step2
orderId: number; // Step3
discountCode?: number; // Step3 (only special)
remarks?: string; // Step4 (only admin)
};
export function OrderForm({
isSpecial,
isAdmin,
}: {
isSpecial: boolean;
isAdmin: boolean;
}) {
const [step, setStep] = useState(1);
const [formData, setFormData] = useState({
customerName: '',
email: '',
phone: '',
orderId: 0,
discountCode: undefined,
remarks: undefined,
});
useEffect(() => {
if (isSpecial) {
// If it is special order, init to discountCode
setFormData((prev) => ({
...prev,
discountCode: 666,
}));
}
}, [isSpecial]);
const handleNextStep = async () => {
try {
if (step === 1) {
stepOneSchema.parse(formData);
setStep(2);
} else if (step === 2) {
stepTwoSchema.parse(formData);
setStep(3);
} else if (step === 3) {
stepThreeSchema(isSpecial).parse(formData);
// If admin user, go to step 4. Otherwise to submit.
if (isAdmin) {
setStep(4);
} else {
await handleSubmit();
}
}
} catch (e) {
console.error(e);
}
};
const handleSubmit = async () => {
try {
// Only Step4, validate stepFourSchema
if (isAdmin && step === 4) {
stepFourSchema.parse(formData);
}
await api.post('/orders', formData);
alert('Succeeded order!');
} catch (e) {
console.error(e);
alert('Denied order...');
}
};
return (
{step === 1 && (
)}
{step === 2 && (
setStep(1)}
onNext={handleNextStep}
/>
)}
{step === 3 && (
setStep(2)}
onNext={handleNextStep}
showDiscountField={isSpecial}
/>
)}
{step === 4 && (
setStep(3)}
onSubmit={handleSubmit}
/>
)}
{isSpecial && }
{isAdmin && }
);
}
```
This is a typical case of technical debt — too much logic crammed into a single component, making it hard to maintain, test, or extend.
## Develop
### Run dev server
```sh
pnpm dev
```
### Run tests
```sh
pnpm test
```
### Add UI components (via `shadcn`)
```sh
pnpm dlx shadcn@latest add {componentName}
```
## Related Article
- [Zenn: Refactor technical debt in forms](https://zenn.dev/nyaomaru/articles/technical-debt-code)