diff --git a/API_DOCUMENTATION.md b/docs/api-documentation.md similarity index 100% rename from API_DOCUMENTATION.md rename to docs/api-documentation.md diff --git a/CLASSIFICATION_IMPLEMENTATION.md b/docs/classification-implementation.md similarity index 100% rename from CLASSIFICATION_IMPLEMENTATION.md rename to docs/classification-implementation.md diff --git a/docs/code-cleanup-guide.md b/docs/code-cleanup-guide.md new file mode 100644 index 0000000..e480516 --- /dev/null +++ b/docs/code-cleanup-guide.md @@ -0,0 +1,473 @@ +# Code Cleanup Guide + +This guide documents the cleanup patterns and best practices applied to the codebase, starting with `GroceryList.jsx`. Use this as a reference for maintaining consistent, clean, and readable code across all files. + +## Table of Contents +1. [Spacing & Organization](#spacing--organization) +2. [Comment Formatting](#comment-formatting) +3. [Code Simplification](#code-simplification) +4. [React Performance Patterns](#react-performance-patterns) +5. [Cleanup Checklist](#cleanup-checklist) + +--- + +## Spacing & Organization + +### Two-Line Separation +Use **2 blank lines** to separate logical groups and functions. + +**Before:** +```javascript +const handleAdd = async (itemName, quantity) => { + // function body +}; +const handleBought = async (id) => { + // function body +}; +``` + +**After:** +```javascript +const handleAdd = async (itemName, quantity) => { + // function body +}; + + +const handleBought = async (id) => { + // function body +}; +``` + +### Logical Grouping +Organize code into clear sections: +- State declarations +- Data loading functions +- Computed values (useMemo) +- Event handlers grouped by functionality +- Helper functions +- Render logic + +--- + +## Comment Formatting + +### Section Headers +Use the `=== Section Name ===` format for major sections, followed by 2 blank lines before the next code block. + +**Pattern:** +```javascript +// === State === +const [items, setItems] = useState([]); +const [loading, setLoading] = useState(true); + + +// === Data Loading === +const loadItems = async () => { + // implementation +}; + + +// === Event Handlers === +const handleClick = () => { + // implementation +}; +``` + +### Common Section Names +- `=== State ===` +- `=== Data Loading ===` +- `=== Computed Values ===` or `=== Sorted Items Computation ===` +- `=== Event Handlers ===` or specific groups like `=== Item Addition Handlers ===` +- `=== Helper Functions ===` +- `=== Render ===` + +--- + +## Code Simplification + +### 1. Optional Chaining +Replace `&&` null checks with optional chaining when accessing nested properties. + +**Before:** +```javascript +if (existingItem && existingItem.bought === false) { + // do something +} +``` + +**After:** +```javascript +if (existingItem?.bought === false) { + // do something +} +``` + +**When to use:** +- Accessing properties on potentially undefined/null objects +- Checking nested properties: `user?.profile?.name` +- Method calls: `item?.toString?.()` + +**When NOT to use:** +- When you need to check if the object exists first (use explicit check) +- For boolean coercion: `if (item)` is clearer than `if (item?.)` + +--- + +### 2. Ternary Operators +Use ternary operators for simple conditional assignments and returns. + +**Before:** +```javascript +let result; +if (condition) { + result = "yes"; +} else { + result = "no"; +} +``` + +**After:** +```javascript +const result = condition ? "yes" : "no"; +``` + +**When to use:** +- Simple conditional assignments +- Inline JSX conditionals +- Return statements with simple conditions + +**When NOT to use:** +- Complex multi-line logic (use if/else for readability) +- Nested ternaries (hard to read) + +--- + +### 3. Early Returns +Use early returns to reduce nesting. + +**Before:** +```javascript +const handleSuggest = async (text) => { + if (text.trim()) { + // long implementation + } else { + setSuggestions([]); + setButtonText("Add Item"); + } +}; +``` + +**After:** +```javascript +const handleSuggest = async (text) => { + if (!text.trim()) { + setSuggestions([]); + setButtonText("Add Item"); + return; + } + + // main implementation without nesting +}; +``` + +--- + +### 4. Destructuring +Use destructuring for cleaner variable access. + +**Before:** +```javascript +const username = user.username; +const email = user.email; +const role = user.role; +``` + +**After:** +```javascript +const { username, email, role } = user; +``` + +--- + +### 5. Array Methods Over Loops +Prefer array methods (`.map()`, `.filter()`, `.find()`) over traditional loops. + +**Before:** +```javascript +const activeItems = []; +for (let i = 0; i < items.length; i++) { + if (!items[i].bought) { + activeItems.push(items[i]); + } +} +``` + +**After:** +```javascript +const activeItems = items.filter(item => !item.bought); +``` + +--- + +## React Performance Patterns + +### 1. useCallback for Event Handlers +Wrap event handlers in `useCallback` to prevent unnecessary re-renders of child components. + +```javascript +const handleBought = useCallback(async (id, quantity) => { + await markBought(id); + setItems(prevItems => prevItems.filter(item => item.id !== id)); + loadRecentlyBought(); +}, []); // Add dependencies if needed +``` + +**When to use:** +- Handler functions passed as props to memoized child components +- Functions used as dependencies in other hooks +- Functions in frequently re-rendering components + +--- + +### 2. useMemo for Expensive Computations +Use `useMemo` for computationally expensive operations or large transformations. + +```javascript +const sortedItems = useMemo(() => { + const sorted = [...items]; + + if (sortMode === "az") { + sorted.sort((a, b) => a.item_name.localeCompare(b.item_name)); + } + + return sorted; +}, [items, sortMode]); +``` + +**When to use:** +- Sorting/filtering large arrays +- Complex calculations +- Derived state that's expensive to compute + +--- + +### 3. React.memo for Components +Wrap components with `React.memo` and provide custom comparison functions to prevent unnecessary re-renders. + +```javascript +const GroceryListItem = React.memo( + ({ item, onClick, onLongPress }) => { + // component implementation + }, + (prevProps, nextProps) => { + return ( + prevProps.id === nextProps.id && + prevProps.item_name === nextProps.item_name && + prevProps.quantity === nextProps.quantity && + prevProps.item_image === nextProps.item_image + ); + } +); +``` + +**When to use:** +- List item components that render frequently +- Components with stable props +- Pure components (output depends only on props) + +--- + +### 4. In-Place State Updates +Update specific items in state instead of reloading entire datasets. + +**Before:** +```javascript +const handleUpdate = async (id, newData) => { + await updateItem(id, newData); + loadItems(); // Reloads entire list from server +}; +``` + +**After:** +```javascript +const handleUpdate = useCallback(async (id, newData) => { + const response = await updateItem(id, newData); + + setItems(prevItems => + prevItems.map(item => + item.id === id ? { ...item, ...response.data } : item + ) + ); +}, []); +``` + +**Benefits:** +- Faster updates (no server round-trip for entire list) +- Preserves scroll position +- Better user experience (no full re-render) + +--- + +## Cleanup Checklist + +Use this checklist when cleaning up a file: + +### Structure & Organization +- [ ] Group related state variables together +- [ ] Use 2-line spacing between logical sections +- [ ] Add section comments using `=== Format ===` +- [ ] Order sections logically (state → data loading → computed → handlers → helpers → render) + +### Code Simplification +- [ ] Replace `&&` null checks with optional chaining where appropriate +- [ ] Convert simple if/else to ternary operators +- [ ] Use early returns to reduce nesting +- [ ] Apply destructuring for cleaner variable access +- [ ] Use array methods instead of loops + +### React Performance +- [ ] Wrap stable event handlers in `useCallback` +- [ ] Use `useMemo` for expensive computations +- [ ] Consider `React.memo` for list items or frequently re-rendering components +- [ ] Update state in-place instead of reloading from server + +### Consistency +- [ ] Check naming conventions (camelCase for functions/variables) +- [ ] Ensure consistent spacing and indentation +- [ ] Remove unused imports and variables +- [ ] Remove console.logs (except intentional debugging aids) + +### Testing After Cleanup +- [ ] Verify no functionality broke +- [ ] Check that performance improved (using React DevTools Profiler) +- [ ] Test all interactive features +- [ ] Verify mobile/responsive behavior still works + +--- + +## Example: Before & After + +### Before Cleanup +```javascript +import { useState, useEffect } from "react"; + +export default function MyComponent() { + const [items, setItems] = useState([]); + const [loading, setLoading] = useState(true); + const loadItems = async () => { + setLoading(true); + const res = await getItems(); + setItems(res.data); + setLoading(false); + }; + useEffect(() => { + loadItems(); + }, []); + const handleUpdate = async (id, data) => { + await updateItem(id, data); + loadItems(); + }; + const handleDelete = async (id) => { + await deleteItem(id); + loadItems(); + }; + if (loading) return
Loading...
; + return ( +Loading...
; + + return ( +Loading...
; + return (